我正在编写一个脚本,该脚本将 files ( filename
...) 作为参数,并将 stdout 和 stderr 重定向到 name 的文件filename.output
。文件中包含命令,我只想 bash 一次(以防文件中的命令不应运行多次,即mkdir
或rmdir
)。我发现,当迭代参数时,此命令有效:
bash $a &> "$(basename $a).output"
但是,我还想使用此命令的错误状态,以防.output
由于某种原因无法创建:
if ! bash $a &> "$(basename $a).output"
then
echo >&2 "failed to create $(basename $a).output"
fi
当我这样做时,我的 if 语句总是评估为 true,这我认为是因为 stdout 或 stderr 需要重定向失败,而不是两者。我正在测试的命令很少会同时产生 stderr 和 stdout(即像这样的命令date
会产生 stdout,但不会产生 stderr,因此会导致非零返回值,因为 stderr 无法重定向)。
我对代码无法正常运行的原因的分析是否正确?如果是,有没有办法分别检查 stdout 重定向和 stderr 重定向的失败,以便我准确显示.output
未创建的时间?
编辑:我发现问题实际上在于组件bash "$a"
,因为任何时候$a
都有一个带有产生错误的命令的文件,整个 if 语句的计算结果为 true。我想现在我的问题是,是否存在重定向 stdout 和 stderr 会导致我应该注意的错误的情况?
答案1
如果你这样做
if ! bash $a &> "$(basename $a).output"; then
如果重定向中出现错误,或者脚本运行但返回非零退出状态,则 if 语句的主分支将运行。该&> file
运算符与 相同> file 2>&1
,它会重定向 stdout 和 stderr,但由于只涉及一个文件,因此您很难找到一种方法来使其中一个重定向成功,而另一个重定向失败。由于创建文件的各种原因,例如权限问题、不存在的路径、磁盘已满,重定向可能会失败。
让我们创建一个测试脚本:这只会打印一些内容,如果给它一个参数,它会错误退出。
$ cat test.sh
#!/bin/bash
echo test script
if [ "$#" != 0 ]; then
echo exiting with error
exit 1
fi
$ chmod +x test.sh
在这里,重定向失败(因为./non-existing-dir/
确实不存在):
$ if ! ./test.sh > ./non-existing-dir/test.output; then
echo "it failed (for some reason)"; fi
bash: ./non-existing-dir/test.output: No such file or directory
it failed (for some reason)
在这里,重定向成功,并且输出被收集到文件中,但脚本本身返回失败状态:
$ rm -f test.output
$ if ! ./test.sh 1 > ./test.output; then
echo "it failed (for some reason)"; fi
it failed (for some reason)
$ cat test.output
test script
exiting with error
您不能错过重定向中的错误;一个将导致命令以非零状态退出。但确切的值尚未定义并且取决于 shell,因此我们无法使用它来区分重定向失败和脚本本身失败。 POSIX Shell 命令语言定义在 2.8.2 命令的退出状态中表示:
如果命令在字扩展或重定向期间失败,则其退出状态应介于 1 到 125(含)之间。
Bash 的手册中也说了类似的事情3.7.1 简单命令扩展。
现在,如果您确实想专门检查重定向中的错误,您可以能这样做,你只需在运行程序之前单独打开重定向即可。例如,我们可以使用这样的脚本来运行我们的程序:
$ cat redir.sh
#!/bin/sh
outfile="${1?please define output file}"
cmd="${2?please define command to run}"
shift 2
if ! exec 9> "$outfile"; then
echo "error: cannot create redirection to '$outfile'"
exit 1
fi
if ! "$cmd" "$@" >&9 2>&9; then
echo "error: script '$cmd' failed"
exit 1
fi
exec 9>&- # close the output fd
现在,检测到失败的重定向如下:
$ bash redir.sh ./non-existing-dir/test.output ./test.sh
redir.sh: line 8: ./non-existing-dir/test.output: No such file or directory
error: cannot create redirection to './non-existing-dir/test.output'
脚本失败也是如此:
$ bash redir.sh ./test.output ./test.sh 1
error: script './test.sh' failed