異なるコマンドの結果を組み合わせる方法を知っています
paste -t',' <(commanda) <(commandb)
同じ入力を別のコマンドにパイプすることを知っています
cat myfile | tee >(commanda) >(commandb)
では、これらのコマンドを組み合わせる方法は?私ができるように
cat myfile | tee >(commanda) >(commandb) | paste -t',' resulta resultb
ファイルがあるとしましょう
myfile:
1
2
3
4
新しいファイルを作りたい
1 4 2
2 3 4
3 2 6
4 1 8
使った
cat myfile | tee >(tac) >(awk '{print $1*2}') | paste
結果は垂直方向に表示されますが、実際には水平方向に貼り付けます。
複数のプロセス置換に対応する場合、特定の順序で出力を取得できるとは限らないため、これを使用することをお勧めします。
paste -t',' <(commanda < file) <(commandb < file)
cat myfile
は高価なパイプラインの略で、出力をファイルまたは変数のいずれかに保存する必要があると思います。
output=$( some expensive pipeline )
paste -t',' <(commanda <<< "$output") <(commandb <<< "$output")
あなたの例を使用して:
output=$( seq 4 )
paste -d' ' <(cat <<<"$output") <(tac <<<"$output") <(awk '$1*=2' <<<"$output")
1 4 2
2 3 4
3 2 6
4 1 8
別の考え:FIFO、および単一のパイプライン
mkfifo resulta resultb
seq 4 | tee >(tac > resulta) >(awk '$1*=2' > resultb) | paste -d ' ' - resulta resultb
rm resulta resultb
1 4 2
2 3 4
3 2 6
4 1 8
yash
シェルには、それを簡単にする独自の機能(パイプラインリダイレクトおよびプロセスリダイレクト)があります。
_cat myfile | (
exec 3>>|4
tee /dev/fd/5 5>(commanda >&3 3>&-) 3>&- |
commandb 3>&- |
paste -d , /dev/fd/4 - 3>&-
)
_
_3>>|4
_(パイプラインリダイレクト)は、書き込み端がfd 3にあり、読み取り端がfd4にあるパイプを作成します。
3>(commanda>&3)
はプロセスリダイレクトで、ksh/zsh/bashプロセス置換に少し似ていますが、リダイレクトを実行し、_/dev/fd/n
_で置換しません。 ksh
の>(cmd)
はyash
のn>(cmd) /dev/fd/n
とほぼ同じです(n
はksh
あなたがコントロールできない)。
zsh
の場合:
pee() (
n=0 close_in= close_out= inputs=() outputs=()
merge_command=$1; shift
for cmd do
eval "coproc $cmd $close_in $close_out"
exec {i}<&p {o}>&p
inputs+=($i) outputs+=($o)
eval i$n=$i o$n=$o
close_in+=" {i$n}<&-" close_out+=" {o$n}>&-"
((n++))
done
coproc :
read -p
eval tee /dev/fd/$^outputs $close_in "> /dev/null &
" exec $merge_command /dev/fd/$^inputs $close_out
)
次に、次のように使用します。
$ echo abcd | pee 'paste -d,' 'tr a A' 'tr b B' 'tr c C'
Abcd,aBcd,abCd
これは この他の質問 から適応されています。ここには、制限に関する詳細な説明とヒントがあります(デッドロックに注意してください!)。
特定の例では、paste
などは必要ありません。標準のツールセットで制限に遭遇した場合、それは、ある方法で実行したいことが別の方法で実行できるためであることがよくあります。といった:
_set 1 2 3 4
while [ "$#" -gt 0 ]
do echo "$1" "$#" "$(($1*2))"
shift;done
_
...印刷する...
_1 4 2
2 3 4
3 2 6
4 1 8
_
あなたが言及したような内容のファイルをあなたのシェル_"$@"
_配列に得ることができます...
_set -f; IFS='
'; set -- $(cat)
_
そして、上記のようなループでarg値を検証するために、初期テストを少し変更することができます...
_while { [ "$1" -eq "${1-1}" ] ;} 2>&"$((2+!$#))"
do echo "$1" "$#" "$(($1*2))"
shift;done 3>/dev/null >outfile
_
...これは、set -- $(cat)
で読み込まれた行に、完全に単一の整数で構成されていない行が含まれている場合にのみ、stderrにエラーを出力します。