次の入力を使用してパイプラインで「検索」を実行します。
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
。
重要:検索プロセスは一度だけ開始したいと思います。
a) これは悪い考えですか?では、どうすればよいですか?
b)これより良いモデルはありますかtee tmp | cut | "lookup" | paste tmp -
?
答え1
これは、出力の複雑さと維持する必要がある形式の程度によって異なります(たとえば、最初の列の長さは常に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
。これを行うには、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 ))
答え2
正しい方法は名前付きパイプを使用するようです。
例:
function datastreamWrapper() {
mypipe=$(mktemp -u)
mkfifo -m 600 "$mypipe"
tee >( cut -f2 | datastream ... > "$mypipe") | paste - "$mypipe"
rm "$mypipe"
}
その後、 datastreamWrapper をパイプラインに配置できます。
cat source.tab | datastreamWrapper | foo