检测Bash管道

时间:2016-08-23 17:27:27

标签: linux bash

我有一个脚本可选择读取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 ...

如果你交换评论条件,你会看到两者现在都正常工作。

1 个答案:

答案 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