入力が次のようになっているパイプラインで「ルックアップ」を実行しようとしています。
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 -
よりも良いパターンはありますか?
これは、出力の複雑さと、維持する必要のあるフォーマットの量によって異なります(たとえば、最初の列は常に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 ))
正しい方法は、名前付きパイプを使用することのようです
例:
function datastreamWrapper() {
mypipe=$(mktemp -u)
mkfifo -m 600 "$mypipe"
tee >( cut -f2 | datastream ... > "$mypipe") | paste - "$mypipe"
rm "$mypipe"
}
次に、datastreamWrapperをパイプラインに配置できます。
cat source.tab | datastreamWrapper | foo