我有一个备份脚本,现在要求它在实际运行同步(以交互方式运行时)之前调用 git pull 脚本。同步按如下方式完成:
rsync aiSP --delete
备份包含此重定向:
exec 2> "${const_logfile}"
git pull脚本有以下两行:
printf '%s\n' "Shall we pull all the gits? "
read -rep "(You will have to enter your git password for each one.) (y or N) " -n1
当 rsync 运行时,其所有进度输出都会显示在终端中(而不会被塞进日志文件中)。rsync 中的任何错误都会添加到日志文件中。
当备份脚本调用 git pull 脚本时,printf 行显示在终端中,但读取的文本被塞入日志文件中(而不显示)。直接调用该脚本时不会发生这种情况。
于是我将这行重定向代码拉入一个仅包含该代码和 git pull 脚本调用的测试脚本中,因此我确定这是罪魁祸首。最后,我将重定向代码直接添加到 git pull 脚本中并直接调用该脚本,读取的文本再次无法显示在终端中并被发送到日志文件。
我希望 printf 文本和读取的文本遵循相同的路线?
我确信有一个简单的解释。或者复杂的。请为我解惑。
编辑:
Raj 很有帮助;谢谢,Raj!
然而,我还想了解更多;因此,如果有人知道有一篇文章讨论了什么是这些非同寻常的消息(Raj 是这样称呼它们的)以及为什么将它们发送到 stderr 是有用的,我很乐意阅读更多相关内容。
另外,关注的人可能想知道 read 的 -p 方面(来自这里):
-p prompt 在尝试读取任何输入之前,显示标准错误提示,不带尾随换行符。仅当输入来自终端时才显示提示。
答案1
回答的关键是你已经在问题中写过的内容:“当 rsync 运行时,其所有进度输出都会显示在终端中(并且不会被塞进日志文件中)。rsync 中的任何错误都会添加到日志文件中。”
这是因为该exec
命令重定向了标准误差(但不是标准输出)将运行脚本的 shell 的输出写入日志文件。常规rsync
输出写入 stdout(即终端),但错误消息写入 stderr(即日志文件)。
Linux 工具中通常使用的惯例是将“正常”输出写入 stdout,而将任何即使在输出重定向时也应该向用户显示的“异常”消息写入 stderr。
因此,read
提示符也会写入 stderr,因为它旨在显示给用户。另一方面,printf
旨在显示“常规”输出,因此它会写入 stdout(如果您想写入 stderr,您可以随时使用printf ... >&2
)。
类似地,如果您希望read
将提示写入 stdout,则可以使用read ... 2>&1
。但如果 stdout 被重定向怎么办?
正确的解决方案是记住“初始” stderr,然后将其重定向到exec
另一个文件描述符中(我们希望它是一个终端),并使用该描述符在“原始” stderr 上显示提示。
在你引用的那一行之前exec
应该再放一行:
exec 3>&2
exec
在下一个命令重定向之前,这会将文件描述符 2 (stderr) 复制到文件描述符 3。然后在read
命令中使用以下重定向:
read ... 2>&3
这应该将提示read
重定向到文件描述符 3,即原来的重定向之前的标准错误。