Linuxパイプとtee コマンド


# パイプ

パイプ(pipe)：その名の通り、水道管です。一方から入れて、もう一方から出します。
shell 中では、二つ以上のコマンド（プログラム|プロセス）を連結して、前のコマンドの出力を次のコマンドの入力として使うことができます。
まるで、水道管で二つのコマンドを繋ぐようにです；
パイプを使用する際、前のコマンドは標準出力をサポートしている必要があり、後のコマンドは標準入力をサポートしている必要があります:

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3515709/cd7be883-dcfd-8e05-c4f6-d77432b9741c.png)

## 書式
COMMAND1|COMMAND2|COMMAND3|..
機能説明：
コマンド1のSTDOUTをコマンド2のSTDINに送り、コマンド2のSTDOUTをコマンド3のSTDINに送ります。
全てのコマンドは、現在のshellプロセスの子shellプロセスで実行されます。
様々なツールの機能を組み合わせることができます。
注意：STDERRはデフォルトでパイプによって転送されないので、2>&1 もしくは |& を使って実現することができます。書式は以下の通りです:
COMMAND1 2>&1 | COMMAND2
COMMAND1 |& COMMAND2

### 例：
```shell
[root@rocky86 ~]# echo 1+2+3|bc
6

[root@rocky86 ~]# cat /var/log/messages | more

[root@rocky8 ~]# ls --help | grep size

[root@rocky86 ~]# echo $PATH | tr ':' '\n'
/usr/local/sbin
/usr/local/bin
/usr/sbin
/usr/bin
/root/bin
```

### 複数のパイプの使用例
```shell
[root@rocky86 ~]# echo $PATH | tr ':' '\n' | sort
/root/bin
/usr/bin
/usr/local/bin
/usr/local/sbin
/usr/sbin

[root@rocky86 ~]# ifconfig | head -n 2 | tail -n 1 | tr -s ' ' | cut -d" " -f3
10.0.0.158
```

### 例：標準出力と標準エラー出力を同時にパイプで使用
```shell
[root@rocky86 ~]# ls fstab null 2>&1 | tr 'a-z' 'A-Z'
LS: CANNOT ACCESS 'NULL': NO SUCH FILE OR DIRECTORY
FSTAB

[root@rocky86 ~]# ls fstab null |& tr 'a-z' 'A-Z'
LS: CANNOT ACCESS 'NULL': NO SUCH FILE OR DIRECTORY
FSTAB
```

### 例：メールサービスの実装
```shell
[root@rocky86 ~]# vim /etc/mail.rc
set from=mooreyxia@gmail.com
set smtp=smtp.gmail.com
set smtp-auth-user=mooreyxia@gmail.com
set smtp-auth-password=meenopnxjawzbfcc
set smtp-auth=login
set ssl-verify=ignore

echo "test email" | mail -s "test" someone@gmail.com
```

### 例：ユーザーパスワードの変更
```shell
[root@rocky86 ~]# passwd --stdin jose
ユーザー jose のパスワードを変更中。
moore
passwd: 認証トークンが正常に更新されました。

[root@centos8 ~]# cat pass.txt
centos
[root@rocky86 ~]# passwd --stdin jose < pass.txt
ユーザー jose のパスワードを変更中。
passwd: 認証トークンが正常に更新されました。
[root@rocky86 ~]# cat pass.txt | passwd --stdin jose
ユーザー jose のパスワードを変更中。
passwd: 認証トークンが正常に更新されました。
[root@rocky86 ~]# echo magedu | passwd --stdin jose
ユーザー jose のパスワードを変更中。
passwd: 認証トークンが正常に更新されました。
[root@rocky86 ~]# echo moore | passwd --stdin jose &> /dev/null
```

# tee コマンド
標準入力を指定された各ファイルにコピーし、標準出力に表示します。
## 書式
tee [OPTION]... [FILE]...
### よく使われるオプション
-a|--append # 内容を既存のファイルに追加します（上書きせず）。
-i|--ignore-interrupts # 中断シグナルを無視します。
-p # 非パイプへの書き込みのエラーを探知します。warn-nopipe を使用します。
--output-error[=モード] # 書き込みエラー時の挙動を設定します（warn|warn-nopipe|exit|exit-nopipe）。

cmd1 | tee [-a] filename | cmd2

### 例：
#### 標準入力を受け取り、標準出力に表示し、ファイルに書き込みます。
```shell
[root@rocky86 ~]# tee tee.log
```
#### パイプリダイレクト
```shell
[root@rocky86 ~]# echo hello | tee tee.log
hello
```
#### tee.log の中身は hello、端末出力は HELLO
```shell
[root@rocky86 ~]# echo hello | tee tee.log | tr 'a-z' 'A-Z'
HELLO
```
#### tee.log と端末出力の両方が大文字です。
```shell
[root@rocky86 ~]# echo hello | tr 'a-z' 'A-Z' | tee tee.log
HELLO
```
#### 追加
```shell
[root@rocky86 ~]# echo hello | tr 'a-z' 'A-Z' | tee -a tee.log
HELLO
```

#### 数字加算：
```shell
[root@rocky86 ~]# echo {1..100} | tr ' ' + | bc
5050
[root@rocky86 ~]# echo {1..100..2} | tr ' ' + | bc
2500
[root@rocky86 ~]# seq -s + 1 100 | bc
5050
[root@rocky86 ~]# seq -s+ 1 2 100 | bc
2500
```

#### 多行入力：
```shell
[root@rocky86 ~]# cat <<EOF | tee tee.log
> 123
> 456
> EOF
123
456
```