想象一下这样的命令行:
my-script -foo $(no-such-cmd)
$(no-such-cmd)
将导致错误,但我找不到方法让脚本知道存在问题。 set -e
似乎不起作用。有办法吗?
这是我在尝试处理文件中的参数时遇到的问题的一部分。 我正在逐行读取文件并尝试检测错误。
这是一个例子。我已经从文件中硬编码了几行假装行。
function err_handler
{
ehs=1
echo "bad thing happened"
}
function fxn
{
echo fxn "$@"
return 0
}
function doit
{
ehs=0
trap err_handler ERR
eval fxn "$@"
eval_status=$?
trap "" ERR
echo ehs $ehs ev $eval_status
}
line='-x good'
doit $line
line='-x $(no-such-cmd)'
doit $line
和输出:
> ./line.sh
fxn -x good
ehs 0 ev 0
./line.sh: line 17: no-such-cmd: command not found
fxn -x
ehs 0 ev 0
请注意错误消息是如何显示的,但陷阱没有触发,退出状态也没有反射(reflect)它。
===============回答下面提出的一些问题===============
@Barmar - 扩展是在调用 doit 之前发生的,但它的工作是因为 doit_init。错误被捕获。我可以将此代码添加到我的实际代码中的循环中。
@user1934428 - 我想捕获从文件读取的开关中出现的任何错误。这个 $(no-such-cmd) 只是一种简单的方法来展示一个难以捕捉的方法。
@charles duffy - 我不是试图将代码放入变量中,而是从文件中读取命令的开关/参数。
@Willian Pursell - 我无法控制输入。我需要依赖用户正确引用参数。
最佳答案
所以永远不要打电话my-script -foo $(no-such-cmd)
。先进行变量赋值,然后调用命令。
if ! arg=$(no-such-cmd); then
echo "no-such-cmd failed!"
exit 2
fi
my-script -foo "$arg"
围绕 eval
破解您的解决方案和doit
和trap err
$(..)
之间的进程间通信子 shell 和父 shell 将无法维护且不可读。无论如何,你必须分享你的trap ERR
与子壳。而且,您必须进行从子 shell 到父 shell 的进程间通信 - 它们是单独的进程。在下面的示例中使用了一个信号。
此外,在下面,我将解析命令参数并在不同的阶段执行命令。请注意,变量赋值等于最后执行的命令。以args=($(no-such-cmd))
为例最后执行的命令是 no-such-cmd
在这种情况下,分配会失败并返回 127 退出代码。然而,args=($(no-such-cmd) $(true))
最后执行的命令是 true
,在这种情况下,第一个子 shell 会向父 shell 发送 SIGUSR1 以传达有关错误的信息。
#!/bin/bash
err_handler() {
# Just communicate to parent process that we failed.
kill -s SIGUSR1 "$parent"
}
fxn() {
echo fxn "$@"
}
doit_init() {
trap err_handler ERR
# just set variable err on SIGUSR1
trap err=1 SIGUSR1
# inherit ERR
set -E
}
doit() {
echo "+ fxn $*"
err=0
local args=()
parent=$$
eval "args=($*)"
ret=$?
if ((ret)); then
echo "parsing args failed with $ret"
return 1
fi
if ((err)); then
echo "any command substitution while expanding arguments failed"
return 1
fi
fxn "${args[@]}"
ret=$?
if ((ret)); then
echo "Calling fxn failed $ret"
return 1
fi
}
doit_init
line='-x good'
doit "$line"
# shellcheck disable=SC2016
line='-x $(no-such-cmd)'
doit "$line"
# shellcheck disable=SC2016
line='-x $(no-such-cmd) $(true)'
doit "$line"
执行脚本的结果是:
$ ./script.sh
+ fxn -x good
fxn -x good
+ fxn -x $(no-such-cmd)
./script.sh: line 30: no-such-cmd: command not found
parsing args failed with 127
+ fxn -x $(no-such-cmd) $(true)
./script.sh: line 30: no-such-cmd: command not found
any command substitution while expanding arguments failed
使用 shellcheck 检查您的脚本。不要将命令参数存储在字符串中 - 更喜欢 bash 数组。更喜欢引用命令替换。
关于bash - 提供给 bash 脚本或文件的选项中的错误检测,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/77729270/