読者です 読者をやめる 読者になる 読者になる

日々之迷歩

世の中わからんことだらけ

ITが複雑で難しくなっていく様に翻弄される日々です

パイプラインに横槍

シェル芸 Shell Mac

シェル芸と言えば、一糸乱れぬ一筋のストリームが流れる事に心奪われ、あな美しかなと心躍らせることこそ醍醐味。だがしかし人間たるもの、完璧なものこそ壊したがる・・・

ということで、上田節が卍解! なのをよそに、シェルのパイプラインに横槍を入れざるを得ない心境になったため、現状理解していることをまとめてみたよ。大きく4パターン也。

1. 文字列やファイルの乱入

1.1. 文字列乱入

シェルの ( ) おまとめ記法とcatの組み合わせで、文字列を混ぜ込むことが出来るのだよ。

$ seq 2 | (echo 'Header'; cat; echo 'Footer')
Header
1
2
Footer

bcコマンドで2進数表示させたい時などに使っている。

$ seq 5 | (echo 'obase=2'; cat) | bc
1
10
11
100
101

1.2. ファイル乱入

catでファイル名に'-'を使うと、標準入力になる。他にもファイル名を-にすると標準入力になるコマンドが存在する。GNU grepのフィルタモードとか。

$ cat data 
1
2

$ seq 11 12 | cat data -
1
2
11
12

ローテーションして圧縮したログと、現在のログを時間順に合体させる時に使っている。

$ ls -tr /var/log/httpd-access.log.*.bz2 |\
> xargs zcat |\
> grep -v 'logfile turned over' |\
> cat - /var/log/httpd-access.log

2. ファイルにぶん投げ

teeコマンドでファイルに書き出せる。まあ基本か。書き出すファイル名は複数指定可。

$ seq 3 | tee num1 num2 | gtac
3
2
1

$ cat num1
1
2
3

$ cat num2
1
2
3

処理を確認したいコマンドがある時(デバッグ)、前後に挟み込んで使っている。

$ ... | tee before | コマンド | tee after | ...
Process Substitutionについて

次に進む前にProcess Substitutionというシェルの機能について。kshbashzsh限定の機能だが、個人的には結構好きなのだ。

コマンドに対する入出力を、ファイルのように指定することが出来る。

  • コマンドの標準出力を入力ファイルとして<(コマンド)
  • コマンドの標準入力を出力ファイルとして>(コマンド)

言葉だけでは分かりにくいので具体例を。例えばdiffコマンド。ご存知2つのファイルの差分を取る。が、2つのコマンド出力の差分を取りたい場合はこうじゃ。

$ \ls -1
a
b

$ \ls -a1
.
..
.dot
a
b

$ diff <(\ls) <(\ls -a)
0a1,3
> .
> ..
> .dot

さて、Process Substitutionの機能を踏まえたところで続きを。

3. 別のコマンドが乱入

echoとcatの組み合わせで文字列を混ぜ込む。先ほどのbcコマンドで2進数表示をする例。

$ seq 5 | cat <(echo 'obase=2') - | bc
1
10
11
100
101

これは下記の記事でも利用していた機能。papiro.hatenablog.jp

4. 別のコマンドにぶん投げ

teeとの組み合わせで、別の複数のコマンドに流れを分岐出来るのだ。

$ seq 3 | tee >(gtac > reverse) >(gsort -R > random) | wc -l
       3

$ cat reverse 
3
2
1

$ cat random 
3
1
2

途中結果をtrコマンドに渡してCSV保存するとかに使える。

$ awk '{print substr($4,2,11),substr($4,14,2)}' acccess_log |\
> count 1 2 |\
> tee >(tr ' ' ',' > syukei.csv) |\
> map num=1 |\
> keta | head -n 3
          *  00  01 05 06 07 08 09  10   11  12  13   14   15   16   17   18  19   20  21  22  23
03/Apr/2008   0   0  0  0  0  0  0   0    0   0   0    1    2    0    0    0   0    0   0   0   0
04/Apr/2008   0   0 27  0  0  0  0   0    0   0  15   41    0    0    0    0   0    0   0   0   0
07/Apr/2008   0   0  0  0  0  0  0   0    2   0   0    0    0    0    0    0   0    0   0   0   0
10/Apr/2008   0   0  0  0  0  0  0   0    0   0   0    0    0    0    0    0   0    0   6   0   0

$ head -n 3 syukei.csv 
03/Apr/2008,14,1
03/Apr/2008,15,2
04/Apr/2008,05,27

ところで、ゴールデンウイークシェル芸問題のまとめ – 上田ブログにも紹介されていたmoreutilsのsponge。moreutils調べてたらpeeというコマンド発見。

Process Substitution同様に、パイプライン複数に分けることが出来る。ただ、peeコマンド以降の出力は打ち止めのようだ。

$ seq 3 | pee 'gtac > reverse' 'gsort -R > random'

シェル芸人達には基本だったかもしれないが、これらを応用すればパイプラインに分岐を作ることが出来て便利になるかもしれない、混乱するかもしれない、それはあなた次第・・・