Bash shell 中的 echo 命令是否会在没有显式输出重定向的情况下向 stderr 写入任何内容?

问题描述 投票:0回答:1

许多其他命令/二进制文件会(例如

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 这样的语言。

linux bash error-handling echo io-redirection
1个回答
0
投票

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
© www.soinside.com 2019 - 2024. All rights reserved.