環境
$ bash --version
GNU bash, version 4.3.30(1)-release (x86_64-apple-darwin14.0.0)
パイプ (pipe) commandA | commandB
正式にはPipeline。|&
でも動く(2019/03/16補足: |&
では標準出力と標準エラー出力を次のプロセスの標準入力につなぎます)。
$ man bash
より
Pipelines
A pipeline is a sequence of one or more commands separated by one of the control
operators | or |&.
$ seq 1 5 | grep 1
1
$ seq 1 5 |& grep 1
1
[パイプ + α] 標準入力自体を解釈して実行 commandA 'commandB' | bash
$ echo yes | bash
y
y
y
y
...
# yesコマンドが実行される
$ yes 'echo $RANDOM' | bash
212
16621
7312
2233
19266
2762
$ echo $$; echo 'echo $$' | bash
88208
88278
# プロセスのIDは違う
$ man bash
より
DESCRIPTION
Bash is an sh-compatible command language interpreter that executes commands read
from the standard input or from a file.
単に「標準入力かファイルを解釈して実行するよ」とあるだけで、特にこのテク自体には名前はないのかも。
[パイプ + α] xargs commandA | xargs -I@ commandB @
標準入力を次のコマンドの引数にする。ただのxargsの応用例。よく使う慣用句。
$ echo "-al" | xargs -I@ ls @
drwxr-xr-x+ 133 greymd greymd 4522 Dec 17 13:34 .
drwxr-xr-x 7 root greym 238 Oct 25 2014 ..
# ls -al が実行される
コマンド置換 (command substitution) commandA $(commandB)
commandA `commandB`
とも書ける。
commandの実行結果が文字列として認識される。
$ ls $(echo '-al')
drwxr-xr-x+ 133 greymd greymd 4522 Dec 17 13:34 .
drwxr-xr-x 7 root greym 238 Oct 25 2014 ..
# ls -al が実行される
$ `echo "yes"`
y
y
y
y
y
# yesが実行される
$()
は入れ子にできる`
(backtick)は入れ子にできない。
$()
はcshとかtcshじゃ動かない。
$ cat $(echo $(echo "/etc/passwd"))
プロセス置換 (process substitution)
このページが良くまとまってた。
出力対象のプロセス置換 commandA >(commandB)
$ seq 10 | tee >(grep -v 1 > output)
1
2
3
4
5
6
7
8
9
10
$ cat output
2
3
4
5
6
7
8
9
commandA | tee >(commandB) | commandC
という形式で使うと、commandA
の出力をcommandB
とcommandC
の両方で扱え、かつ両方とも標準出力に出せる。一旦パイプ
が枝分かれになって、出口で合流した感じ。
$ seq 10 | tee >(grep 1) | grep 2
1 # grep 1 による出力
10 # grep 1 による出力
2 # grep 2 による出力
入力対象としてのプロセス置換 commandA <(commandB)
これはよく使う。<(command)
はcommand
の実行結果が記載されたファイルのように振る舞う。
$ cat <(seq 10)
1
2
3
4
5
6
7
8
9
10
# これと挙動としては同じ
$ seq 10 > tmp
$ cat tmp
1
2
3
4
5
6
7
8
9
10
ファイルのように振る舞うんでしょ?ファイル名は?→ファイルディスクリプタでした。
$ echo <(seq 10)
/dev/fd/63
複合コマンド(Compound Commands) (commandA; commandB;)
{commandA; commandB;}
複数のコマンドをコロンで区切って、出力を合体させる。
()
はサブシェル (subshell)、{}
は何と表現すればよいのか。
$ (echo '123'; echo '456')
123
456
{}
はサブシェルではなく、現在のプロセスで実施されるとのこと。確かにサブシェルだけプロセスIDが違う。
$ echo $BASHPID; (echo $BASHPID;); { echo $BASHPID; }
75461
76279
75461