web-dev-qa-db-ja.com

`ティーよりも良い方法|カット| ... |貼り付け `

入力が次のようになっているパイプラインで「ルックアップ」を実行しようとしています。

alice  5
bob    7
...

データベースの2番目の列でコードを検索し、対応する名前を返し、元のデータと検索したデータを追跡し続けたいと思います。

cat source.tab | \
  tee foo.tmp | \
  cut -f 2 | \
  dbstream ... -s "select(select name from my_lookup where code=?)" | \
  paste foo.tmp -

結果は次のようになります。

alice  5  foo
bob    7  bar
...

cat source.tabが他の前処理を行う本当に長いパイプラインであると少し想像してみてください。そして、そのdbstream ..は、他のコマンド、たとえばwget | jqである可能性があります。

重要:ルックアッププロセスを1回だけ開始したい。

a)これはひどい考えですか?もしそうなら、代わりに何をすべきですか?
b)tee tmp | cut | "lookup" | paste tmp -よりも良いパターンはありますか?

5
Neil McGuigan

これは、出力の複雑さと、維持する必要のあるフォーマットの量によって異なります(たとえば、最初の列は常に8文字の長さですか?など)。ただし、whileループは機能する可能性があります

cat source.tab | while read -r name id
do
  echo "$name $id $(dbstream .... code=$id)"
done

ループ内で何が起こるかを好きなようにフォーマットするように変更できます。

cat source.tab | while read -r name id
do
  res=$(dbstream ... code=$id)
  printf "%10s %5d %s" $name $id $res
done

コメントによると、dbstreamを1回だけ呼び出す必要があります。これには、出力を入力と同じ順序に保つためにdbstreamが必要です。

dbstreamプログラムの簡単な例を次に示します。

#!/bin/sh
for a in "$@"
do
  echo dbstream $$ sees $a
done

PIDを出力に含めて、一度だけ呼び出されることを示すことができるようにします。

これで、pasteとプロセス置換を使用できます。

$ paste source.tab <(./dbstream $(awk '{print $2}' source.tab ))
alice 1 dbstream 20671 sees 1
bob   2 dbstream 20671 sees 2

さて、source.tabは遅いプロセスです一時ファイルを使用することをお勧めします

例えば

#!/bin/bash

tmp=`mktemp`

trap '/bin/rm -f $tmp ; exit' 0 1 2 3 15

cat source.tab > $tmp
paste $tmp <(./dbstream $(awk '{print $2}' $tmp ))
8
Stephen Harris

正しい方法は、名前付きパイプを使用することのようです

例:

function datastreamWrapper() {

  mypipe=$(mktemp -u)
  mkfifo -m 600 "$mypipe"

  tee >( cut -f2 | datastream ... > "$mypipe") | paste - "$mypipe"

  rm "$mypipe"
}

次に、datastreamWrapperをパイプラインに配置できます。

cat source.tab | datastreamWrapper | foo
0
Neil McGuigan