暗无天日

=============>DarkSun的个人博客

使用管道要注意的几个点

  1. 管道中的每个命令都是在自己的子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}"
    
  2. 管道的返回值只由最后哪个命令的返回值来决定,除非指定了 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
    
  3. 打开命名管道时,若只打开它的一端,则该操作会被挂起,直到它的读写两端都被打开。

    下面操作会被挂起

    mkfifo t
    exec 4>t
    

    而下面操作不会挂起

    mkfifo t
    exec 4<>t
    
  4. 有些程序会把输出内容缓存起来,直到缓存区满了或者收到结束符号才将内容真正输出。 当使用这种程序写入命名管道时,要特别注意,确保程序真的有把内容输出道命名管道,而不是缓存起来,否则很容易导致操作挂起
  5. 不要真的把命名管道当成文件来用,当命名管道的读写两端都关闭后,里面的内容会被清掉。