使用管道要注意的几个点
管道中的每个命令都是在自己的子shell中执行的,因此管道中的命令不要尝试去修改父shell中的变量,那样是无效的。
last_line='NULL' seq 1 2 | while read line; do last_line="${line}" # echo ${last_line} done # This will output 'NULL' echo "${last_line}"
正确的做法是改成
last_line='NULL' while read line; do last_line="${line}" done< <(seq 1 2) # 注意< 和 < 之间有个空格 # This will output '2' echo "${last_line}"
管道的返回值只由最后哪个命令的返回值来决定,除非指定了
pipefail
比如,下面这个命令的
$?
会是0
wrong command1 |[[ "a" == "b" ]] |true echo $?
0
若指定了
pipefail
选项,则管道的返回值最后的那个执行失败的命令来决定set -o pipefail wrong command1 |[[ "a" == "b" ]] |true echo $?
1
若你想要知道管道中每条命令的执行情况,则需要查看
PIPESTATUE
变量wrong command1 |[[ "a" == "b" ]] |true echo "${PIPESTATUS[0]}" "${PIPESTATUS[1]}" "${PIPESTATUS[2]}"
127 1 0
打开命名管道时,若只打开它的一端,则该操作会被挂起,直到它的读写两端都被打开。
下面操作会被挂起
mkfifo t exec 4>t
而下面操作不会挂起
mkfifo t exec 4<>t
- 有些程序会把输出内容缓存起来,直到缓存区满了或者收到结束符号才将内容真正输出。 当使用这种程序写入命名管道时,要特别注意,确保程序真的有把内容输出道命名管道,而不是缓存起来,否则很容易导致操作挂起
- 不要真的把命名管道当成文件来用,当命名管道的读写两端都关闭后,里面的内容会被清掉。