忙しい人向けのまとめ
pee コマンドは標準出力を複数のコマンドに同時にパイプできるよ!
teeコマンドってあるじゃん?
tee というコマンドがありますよね。標準入力を標準出力と同時に、ファイルに書き出すコマンドです。よく使うのは、コマンドの出力をroot権限でファイルに書き出したい場合でしょう。
例えば、以下のコマンドは「echoの出力を/etc以下に(root権限で)書き込みたい」という時に初心者がやりがちな間違いです。意図はわかるのですが、この場合 echo コマンドが(無意味に)root権限で起動するものの、リダイレクトはシェルを動かしている一般ユーザー権限で実行されるため、無慈悲にもPermission deniedとなります。
$ sudo echo hoge > /etc/fuga
これを意図通りに動かすには、/etc 以下に書き込むプロセスをroot権限で起動する必要があります。そこで登場するのが tee コマンドなわけです。上記の間違いを tee を使って書き直すと以下のようになります。
$ echo hoge | sudo tee /etc/fuga
そして tee コマンドは、標準入力を複数のファイルに同時に書き込むこともできます。以下の例では、/etc/fuga / etc/piyo /etc/foo /etc/bar という四つのファイルに、同じ内容が書き込まれます。
$ echo hoge | sudo tee /etc/{fuga,piyo,foo,bar}
peeはteeのパイプ版
標準入力の内容をファイルに書き出す tee コマンドに対し、パイプに書き出すのが pee コマンドです*1。
ここまで聞くと「標準入力をパイプに書き出す? 普通にパイプ繋げばいいじゃん」と思うでしょう。pee コマンドの真価は、tee と同様に、出力先を複数指定できるところにあります。
例えばこんな使い方はどうでしょう。
ps コマンドの出力を grep して、特定のプロセスの情報だけを表示したいことがよくあります。こんな感じですね。
$ ps -fe | grep '[z]sh' mizuno 1413882 1413881 0 11:11 pts/0 00:00:01 -zsh
はい、複数のカラムに色々な情報が表示されましたが、この数字って何の意味でしたっけ? ps コマンドは一行目にヘッダが表示されるのですが、プロセス名で grep してしまうと、当然ヘッダは表示されません。そこで一行目だけを表示する、head コマンドと同時にパイプしてみましょう。
$ ps -fe | pee "head -n 1" "grep [z]sh" UID PID PPID C STIME TTY TIME CMD mizuno 1413882 1413881 0 11:11 pts/0 00:00:01 -zsh
ps コマンドの出力が、head と grep それぞれにパイプされ、期待した出力を得ることができました。
なに? grep の条件を複数指定してor検索すればいいじゃんって? ぎゃふん。
それはさておき、コマンドを直列に繋ぐパイプを並列に分岐させられるのは、色々な使い途がありそうです。ただしそれぞれのコマンドの終了順は保証されていないようなので、そこだけは留意する必要がありそうですね。
ちなみに pee は、Ubuntuでは moreutils パッケージに含まれています。このパッケージには色々と便利なコマンドが含まれているので、興味があったら見てみてください。筆者のお勧めは vidir vipe sponge です。
*1:これは「pipeのtee」の略であり、決しておしっこではないと思います。たぶん。
