異なるコマンドの入力を分割して結果を組み合わせる


8

異なるコマンドの結果を組み合わせる方法を知っています

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

結果は垂直になり、水平方向に貼り付けたいと思います。


名前パイプを分離するために2つのストリームを作成し、それらをモニタープログラムと組み合わせる必要がある場合があります。
把友情留在無盐

回答:


8

複数のプロセス置換を使用する場合、特定の順序で出力を取得することが保証されていないため、以下を使用することをお勧めします

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

/ dev / fd / 3-9のようなsthを使用できますか?
user40129

4

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に、読み取り側がfd 4にあるパイプを作成します。

3>(commanda>&3)あるプロセスのリダイレクトは、ビットのksh / zshの/ bashのプロセス置換と同様に、ちょうどリダイレクトを行い、で代用しません/dev/fd/nkshさんは>(cmd)多かれ少なかれ同じであるyashS ' n>(cmd) /dev/fd/n(そこnが選択したファイルディスクリプタでksh、その上には、あなたが制御することはできません)。


3

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

これは、制限に関する詳細な説明とヒント(デッドロックに注意!)が見つかるこの他の質問を基にしています。


0

あなたの特定の例では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)

上記のようなループで引数の値を検証するには、初期テストを少し変更します...

while { [ "$1" -eq "${1-1}" ] ;} 2>&"$((2+!$#))"
do    echo "$1" "$#" "$(($1*2))"
shift;done  3>/dev/null >outfile

...これは、読み込まset -- $(cat)れた行に完全に単一の整数で構成されていない行が含まれている場合にのみ、エラーをstderrに出力します。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.