Tee

tee(1) の拡張版。
http://www.npcguild.org/software/pundits/index.html
こんなことができる。

# 標準入力から読み込んだ行を既存のファイルに追加する
... | Tee -a /var/log/myapp | ...
# 2つのコマンドに同時にパイプ
... | sort ... | Tee '|head -1 >first' '|tail -1 >last' | comm ...

使い道がありそうで思い浮かばない。


Tee を動かすためには同じ作者の xapply というコマンドが必要だ。
xapply は xargs と apply の拡張でこんなことができる。

# カレントディレクトリ下の各ディレクトリに入って make all
xapply '(cd %1 && make all)' */

# 他のディレクトリの同名のファイルと diff
xapply -f 'diff %1 ../version5/%1' manifest | more

# 2つのファイルリストを読み込み、それぞれを diff
# 一方のファイルが存在しない場合は /dev/null とする。
xapply -p/dev/null -f 'diff %1 %2' manifest1 checklist1

# *.c に indent をかける(apply でもできる)。
xapply 'indent' *.c

# xargs と同じ使い方
find ~ksb/bin -type f ! -perm -111 -print | xapply -f -v 'chmod a+x' -

# 入力を /dev/tty にできるところが xargs より優れている
find ... | xapply -f -5 -i /dev/tty 'vi' - - - - -

# これで cat(1) と同じ動作になる
xapply -fn "" /etc/passwd

# 読み込んだ行の順番を変えて引数とする
tr ':' '\012' < /etc/passwd | xapply -7 -nf 'chown %1 %6' - - - - - - - 

こちらもどれも awk や paste があればできそうな気がする。
そもそも apply の利点がよくわからないのだが。


さらに Tee をビルドするためには mkcmd というコマンドが必要。
こんな感じのファイルを書いておくと

letter 'a' {
	named "cEsc"
	init "'%'"
	param "c"
	help "change the escape character"
}

number {
	named "iPass"
	param "count"
	init "1"
	help "number of arguments passed to each command"
}

integer 'P' {
	named "iParallel"
	init "1"
	help "number of tasks to run in parallel"
	param "[jobs]"
	noparam "if (%ypi == (%N = getenv(\"PARALLEL\")) || '\\000' == *%N) {%N = \"3\";}"
	after "if (%n < 1) {%n = 1;}Tasks(%n);"
}

オプションをパースして変数に格納するCのソースを出力してくれるものらしい。
作者は愛用しているとのことだが。


作者の Kevin Braunsdorf 氏は coreutils の test(1) も書いた人のようだ。