8.Pipeline

  1. Definition 定义
  2. Usage 用法
    1. Code-block 代码块
    2. Read value 获得传输值
    3. Exit Code 退出码
    4. Silence Message 静音
    5. Asynchrony 异步
  3. Q&A
    1. < <() vs pipe(管道)
    2. 管道不能使用 TTY

Definition 定义

通常 Pipelines 会简称成 pipe,Pipelines(管道)在 man bash 下的定义如下:

A pipeline is a sequence of one or more commands separated by one of the control operators ‘ ’ or ‘ &’.
  • |& :前一个管道的标准输出标准错误,将成为后一个管道的输入。 等同于 2>&1 |
  • | :前一个管道的标准输出,将成为后一个管道的输入

Each command in a pipeline is executed in its own subshell, which is a separate process (see Command Execution Environment). If the lastpipe option is enabled using the shopt builtin (see The Shopt Builtin), the last element of a pipeline may be run by the shell process. 默认情况下,管道的每一节,都是一个新的 subshell。

Usage 用法

The format for a pipeline is

1
[time [-p]] [!] command1 [ | or |& command2 ] …

Code-block 代码块

1
{ cmd; } | cat

Read value 获得传输值

1
2
3
4
5
$  echo "hello world" | { read x y; echo $x ; echo $y ;}
hello
world
$  echo "hello world" | { a=$(< /dev/stdin); echo "$a"; };
hello world

其他用例,参考 IO 一章。

Exit Code 退出码

The exit status of a pipeline is the exit status of the last command in the pipeline, unless the pipefail option is enabled (see The Set Builtin). If pipefail is enabled, the pipeline’s return status is the value of the last (rightmost) command to exit with a non-zero status, or zero if all commands exit successfully. 默认情况下,退出码是最后一个命令的退出码,但是当开启 pipefail ,退出码将会是最后一个非零的退出码。

PIPESTATUS :An array variable (see Arrays) containing a list of exit status values from the processes in the most-recently-executed foreground pipeline (which may contain only a single command). man

1
2
3
4
5
6
7
$ { ls ./nothing; } | cat &>/dev/null &&  echo "${PIPESTATUS[*]}"
...
$
0 0
$ echo "${PIPESTATUS[1]}"
0
echo "${PIPESTATUS[2]}"

Silence Message 静音

1
2
3
4
5
6
7
8
9
10
11
12
13
# 正常
$ { ls ; } |& cat  
...
# 消除正常流
$ { ls ./nothing; } | cat &>/dev/null
ls: cannot access './nothing': No such file or directory
$  { ls ./nothing; } | cat 1>/dev/null
ls: cannot access './nothing': No such file or directory
# 消除正常流和异常流
$ { ls ./nothing; } 2>&1  | cat &>/dev/null 
$ { ls ./nothing; } |& cat &>/dev/null 
$ { ls ./nothing; } 2>&1  | cat 1>/dev/null 
$ { ls ./nothing; } |& cat 1>/dev/null 

Asynchrony 异步

管道是异步的。执行下面代码,将看见第二个管道的代码优先执行。

1
2
3
4
5
6
7
8
9
#!/usr/bin/env bash
set -x

{
  sleep 5
  echo 111
} |{
  echo 222
}

除了管道以外,& 也可用于异步。

Q&A

< <() vs pipe(管道)

1
2
3
4
5
6
7
8
9
10
11
12
# 从 STDIN 里获得 date
$ echo "hello world" | cat  
hello world

# < <() 实质是读取文件
$ cat < <(echo "hello world")
hello world
# 上下两块代码是相同的。
$ temp_file=$(mktemp)
$ echo "hello world" > $temp_file
$ cat < $temp_file
hello world

另外一个区别是,管道默认使用的是 subshell。man

管道不能使用 TTY

以下代码将会报错 "the input device is not a TTY",原因查看 此处

1
2
3
4
5
{
  echo "docker exec -it pure-ftpd ftp localhost"
} | {
  bash
}