许多其他命令/二进制文件会(例如
wc --wrong-flag
),但echo
是其中之一吗?
上下文:我正在维护其他人的 Bash 脚本,查看其中的以下部分(为了安全起见,稍微进行了编辑):
log_file_path="logs/some_prefix_redacted.$(date +%Y-%m-%d_%H_%M_%S).log"
echo "Running Step 1 - Deleting files from S3 recursively" >> "${log_file_path}" 2>&1
aws s3 rm --recursive s3://s3_path_redacted >> "${log_file_path}" 2>&1
step_1_exit_code="${?}"
echo "Step 1 - Deleting files from S3 recursively finished with exit code ${step_1_exit_code}." >> "${log_file_path}" 2>&1
我想知道我是否需要这些:
2>&1
在 echo 命令的末尾。他们在将 stderr
传输到日志文件之前将 stdout
传输到 stdout
,一般来说,这就是我们在这种情况下想要的 - 我们不想丢失任何相关信息。但是,具体到 echo
命令的情况下,有必要吗?如果没有显式重定向,echo
命令是否会向 stderr
发送某些内容?看起来,如果我尝试将 echo 的 stdout
和 stderr
重定向到当前用户没有权限的同一个文件,那么错误将被转储到常规 stderr
中。无论如何,在使用 stderr
命令时尝试将 stdout
重定向到 echo
到文件似乎是没有用的。
希望不是,希望
echo
是一个......“可信的原始构建块”,因为缺乏更好的词语。
我们的目标是 a) 保留尽可能多的相关信息以供调试之用,b) 保持代码整洁,不编写任何无效或无用的代码。
我尝试过的: 如果我将
echo
或 stderr
重定向到我没有写入权限的文件,我可以使 stdout
输出一些文本到 stderr
,但我仍然不确定是否可以获得 echo
将某些内容输出到 stderr
,无需显式重定向。
我想这是一个单独的问题,但是如果 echo 命令本身失败怎么办?例如,由于某种原因,没有足够的权限来创建或写入日志文件。
$ echo "This won't work" > /root/not_allowed 2>&1
bash: /root/not_allowed: Permission denied
$ echo "${?}"
1
# Huh? I was not even trying to write anything to stderr, but it still failed?
$ echo "Will this work?" 2>/root/not_allowed
bash: /root/not_allowed: Permission denied
我想要一些指示脚本失败的信息。我想我应该尝试从一开始就通过 echo 向日志文件写入一些内容,如果该命令失败,根据退出代码判断,尝试发送有关错误的电子邮件或 Slack 通知。
一个想法是完全抛弃 Bash,用 Python 编写所有内容,因为它有丰富的异常,但是……Python 成功启动的保证较少。也许我使用了错误的版本,也许它缺少正确的
LD_LIBRARY_PATH
值。从这个意义上说,bash 几乎可以保证存在于几乎所有主流 Linux 操作系统上,因此它更可靠,但它在错误检查或管理复杂性方面不如 Python 这样的语言。
Permission denied
是由 bash 编写的,因为它尝试打开您想要将输出重定向到的文件以进行写入。通过重定向 echo
本身的输出,您永远无法摆脱这些错误。
如果你想让 stderr 转到它已经去的地方以外的地方,你必须在某个时候告诉它去其他地方。有几种方法可以做到这一点,而无需一遍又一遍地重复
2>&1
。一些选项:
您可以使用重定向输出来执行程序。
# Execute program with outputs redirected - will apply to any command
# within the script that doesn't explicitly override
bash myscript >/some/log/file 2>&1
您可以在使用
exec
启动脚本后更改整个程序的输出目的地:
# Use exec to change stdout and stderr
exec >/some/log/file 2>&1
echo foo >/file/with/permissions # writes "foo" to /file/with/permissions
echo bar >/file/without/permissions # writes Permission Denied to /some/log/file
您可以通过将一组命令放在一个组中来更改它们的 stderr:
# write the stderr for some set of commands to a file
{
echo foo >/file/with/permissions
echo bar >/file/without/permissions
} >/some/log/file 2>&1
# also works for a function
write_stuff() {
echo foo >/file/with/permissions
echo bar >/file/without/permissions
}
write_stuff >/some/log/file 2>&1
# also works for subshells
(
echo foo >/file/with/permissions
echo bar >/file/without/permissions
) >/some/log/file 2>&1