我有一个脚本可选择读取bash管道输入,这适用于大多数情况。然而当你把它放到fd0上的另一个管道时,我的脚本会读取父管道数据,因为 - 无论出于何种原因 - 在Bash(在Linux上)它们是同一个管道。
#!/bin/bash
numstr=${1}
rdlnk=$(readlink /proc/$$/fd/0)
function get_input() {
## echo "PID: $$, PPID: $PPID " && sleep 500
## What works is:
## if grep -Eq "^pipe:|deleted" <<< "${rdlnk}" && [[ "${rdlnk}" != "$(readlink /proc/$PPID/fd/0)" ]]; then
if grep -Eq "^pipe:|deleted" <<< "${rdlnk}"; then
while IFS= read -r piped_input || break; do numstr="${numstr}${piped_input}"; done
elif [[ -f "${rdlnk}" ]]; then
numstr=$(head -1 "${rdlnk}")
elif [[ -e "${numstr}" ]]; then
numstr=$(head -1 "${numstr}")
fi
}
get_input
echo "the number string ${numstr} ..."
exit 0
我已经解决了这个问题,你可以在代码本身的注释中看到,通过查看父进程fd0。我想知道的是,是否有更好/更合适的方法来做到这一点?
注意:如果您想仔细研究一下,可能需要取消注释第一行并查看ls -al /proc/[PID|PPID]/fd/0
。
要对此进行测试,请将上面的脚本保存到文件/tmp/test.bsh
。
$> for a in {1..5}; do /tmp/test.bsh "$a"; done
the number string 1 ...
the number string 2 ...
the number string 3 ...
the number string 4 ...
the number string 5 ...
$> while read a; do /tmp/test.bsh "$a"; done < <(seq 1 5)
the number string 12345 ...
如果你交换评论条件,你会看到两者现在都正常工作。
答案 0 :(得分:2)
当你深入了解一个shell和一个操作系统的细节时,你应该问这是否真的是你想要的水。
我无法重现你的行为。在我的系统上:
$ while read a; do ./test.sh "$a"; done < <(seq 1 5)
the number string 1 ...
the number string 2 ...
the number string 3 ...
the number string 4 ...
the number string 5 ...
或者,更常规地,
$ seq 1 5 | while read a; do ./test.sh "$a"; done
the number string 1 ...
the number string 2 ...
the number string 3 ...
the number string 4 ...
the number string 5 ...
但这可能是因为该系统不是Linux ......
真正的问题是,如果可以的话,你会关心错误的事情。您正在从文件描述符向后工作,而不是让用户以最方便的方式定义它。
如果您想从标准输入读取,请执行此操作。如果不这样做,请将用户的输入命名为命令行参数。这就是一切的工作原理。当您开始投资fd0的定义方式以及如何调用脚本时,您首先要破坏操作系统定义标准输入和标准输出的目的。然而,无论如何,你必然会引入奇怪的案例。
如果你需要知道标准输入是否具有特定功能 - 因为这会影响你可以用它做什么 - 这就是 stat (1)的用途。或者只是尝试以您想要的方式使用它,并分支出可预测的错误,例如: ESPIPE
。