我有一个简单的脚本,它将输出重定向append
到一个文件。
filename="/home/ronnie/tmp/hello"
date=$(date)
echo "$date" >> $filename
现在,假设我更改date=$(date)
为date= $(date)
会产生错误。
我修改后的脚本:
filename="/home/ronnie/tmp/hello"
date= $(date)
echo "$date" >> $filename 2>> $filename
#Also tried echo "$date" >> $filename 2>&1
我认为上面的脚本会将错误重定向test.sh: line 5: Fri: command not found
到文件hello
,但它只是在文件中输入一个新行,并且错误会打印在我的stdout
.
我的 bash 版本:
ronnier@ronnie:~/tmp$ bash --version
GNU bash, version 4.2.24(1)-release (i686-pc-linux-gnu)
那么,我哪里出错了。
答案1
导致错误的行是date =$(date)
,该错误被发送到 stderr。在此阶段,您不会将 stderr 重定向到任何地方。后续行将 stderr 发送到 $filename,但这不是导致错误的行。
获得所需效果的方法之一是运行脚本并同时将 stderr 定向到其他地方,因此,
./myscript 2>> errors.txt
此时,errors.txt 将包含您的错误。
所以问题是,生成错误的行是脚本本身的错误,而不是由脚本调用的外部命令引起的错误,该命令的输出被重定向。即它是您需要重定向的顶级脚本输出。
答案2
shell 在到达第 5 行时发出错误消息。此时 shell 的错误流不会重定向。
如果您编写date= $(date) 2>/dev/null
,“找不到命令”消息来自 shell,而不是来自错误流被重定向的命令。因此您仍然会看到错误消息。
为了避免看到错误消息,请将整个命令放入一个组中,并从整个组重定向错误流:
{ date= $(date); } 2>/dev/null
使用大括号时,该命令仍然在父 shell 中执行,因此它可以更改其环境和其他状态(不是在这里执行的)。您还可以将命令放入函数体或子 shell 中(括号内的命令,在单独的 shell 进程中执行)。
exec
您可以通过在不带命令名的内置命令上使用重定向来永久重定向 shell 的文件描述符(或至少直到下次更改它们为止) 。
exec 2>/dev/null
# From this point on, all error messages are lost
date= $(date)
…
exec 2>/some/log/file
# From this point on, all error messages go to the specified file