linux - 为什么在 bash 中的 while read 循环中重定向 stdin?

标签 linux bash shell io-redirection

考虑以下示例脚本:

#!/bin/sh

do_something() {
    echo $@
    return 1
}

cat <<EOF > sample.text
This is a sample text
It serves no other purpose
EOF

cat sample.text | while read arg1 arg2 arg3 arg4 arg5; do
    ret=0
    do_something "$arg1" "$sarg2" "$arg3" "$arg4" "$arg5" <&3 || ret=$?
done 3<&1

stdout 重定向为文件描述符 3 的输入的目的是什么? 至少在 Bash 中,省略它似乎没有任何区别。如果它在 bash 以外的任何其他 shell 中执行,它是否有任何影响?

更新

对于那些想知道这是从哪里来的人,这是来自 Debian 的 cryptdisks_start 的简化示例脚本。

最佳答案

这里的明确意图是防止 do_something从阅读 sample.text流,通过确保其标准输入来自其他地方。 如果您没有看到有或没有重定向的行为差异,那是因为 do_something在您的测试中实际上并没有从标准输入中读取数据。

如果你同时拥有 readdo_something从同一个流中读取,然后是 do_something 消耗的任何内容read 的后续实例将无法使用-- 当然,您会在 do_something 的输入中输入非法内容,导致诸如尝试使用错误的加密 key (如果现实世界的用例类似于 cryptmount )等后果。

cat sample.text | while read arg1 arg2 arg3 arg4 arg5; do
    ret=0
    do_something "$arg1" "$sarg2" "$arg3" "$arg4" "$arg5" <&3 || ret=$?
done 3<&1

现在,它是 buggy -- 3<&13<&0 相比是不好的做法,因为它在没有基础的情况下假设 stdout 也可以用作输入——但它确实成功实现了这个目标。


顺便说一下,我会这样写:

exec 3</dev/tty || exec 3<&0     ## make FD 3 point to the TTY or stdin (as fallback)

while read -a args; do           ## |- loop over lines read from FD 0
  do_something "${args[@]}" <&3  ## |- run do_something with its stdin copied from FD 3
done <sample.text                ## \-> ...while the loop is run with sample.txt on FD 0

exec 3<&-                        ## close FD 3 when done.

它有点冗长,需要显式关闭 FD 3,但这意味着如果我们使用附加到 FIFO 的只写端(或任何其他只写的接口(interface)),而不是直接连接到 TTY。


至于这种做法防止的错误,这是一个很常见的错误。例如,请参阅以下有关它的 StackOverflow 问题:

等等

关于linux - 为什么在 bash 中的 while read 循环中重定向 stdin?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41650892/

相关文章:

linux - 使用 shell 脚本查找是否安装了库

linux - 在 Linux Redhat 中更新 PHP

python - 在 C/C++ 和 Python 之间共享内存

Python命令解释器

bash - 删除所有早于 X 天的文件,但至少保留 Y 最年轻的文件

linux - Linux 中的电子邮件目录列表

linux - 程序收到信号SIGSEGV : Segmentation fault - invalid memory reference

linux - 运行 SSH 命令并从 WinSCP 退出而不中断命令

c - Linux 上的 Bash 权限被拒绝

javascript - 如何使用 NodeJS 在 SSH2 上执行多个命令