一時ファイルなしでコマンドが実行された後にのみコマンドを実行する方法はありますか?もう1つの実行中のコマンドと、出力をフォーマットしてcurlを使用してHTTPサーバーに送信する別のコマンドがあります。 commandA | commandB
、commandB
はcurl
を開始し、サーバーに接続してデータの送信を開始します。 commandA
には非常に時間がかかるため、HTTPサーバーはタイムアウトします。 commandA > /tmp/file && commandB </tmp/file && rm -f /tmp/file
好奇心から、一時ファイルなしでそれを行う方法があるかどうか知りたいです。私は試した mbuffer -m 20M -q -P 100
しかし、カールプロセスはまだ最初から開始されます。 Mbufferは、実際にデータを送信してcommandA
が完了するまで待機します。 (データ自体は最大で数百kbです)
これは他のいくつかの回答と似ています。 「moreutils」パッケージがある場合は、sponge
コマンドが必要です。試す
commandA | sponge | { IFS= read -r x; { printf "%s\n" "$x"; cat; } | commandB; }
sponge
コマンドは基本的にパススルーフィルターです(cat
と同様)。ただし、入力全体を読み取るまで出力の書き込みを開始しません。つまり、データを「吸収」し、(スポンジのように)握るとデータを解放します。したがって、ある程度、これは「不正行為」です。重要な量のデータがある場合、sponge
はほぼ確実に一時ファイルを使用します。しかし、それはあなたには見えません。一意のファイル名の選択や後のクリーンアップなど、ハウスキーピングについて心配する必要はありません。
{ IFS= read -r x; { printf "%s\n" "$x"; cat; } | commandB; }
は、出力の最初の行をsponge
から読み取ります。これは、commandA
が完了するまで表示されないことに注意してください。 ThencommandB
を起動し、最初の行をパイプに書き込み、cat
を呼び出して残りの出力を読み取り、パイプに書き込みます。
パイプラインのコマンドは同時に開始されます。後で使用するには、commandA
の出力をどこかに保存する必要があります。変数を使用して一時ファイルを回避できます。
output=$(command A; echo A)
printf '%s' "${output%%A}" | commandB
この問題に対処できる標準のUNIXユーティリティは知りません。 1つのオプションは、awk
を使用してcommandA
出力を累積し、commandB
に一度にフラッシュすることです。
commandA | awk '{x = x ORS $0}; END{printf "%s", x | "commandB"}'
awk
は入力から文字列を構築しているため、これはメモリを大量に消費する可能性があることに注意してください。
小さなスクリプトで要件を解決できます。この特定の亜種は、追加のプロセスを犠牲にして、一時ファイルと潜在的なメモリ占有を回避します。
#!/bin/bash
#
IFS= read LINE
if test -n "$LINE"
then
test -t 2 && echo "Starting $*" >&2
(
echo "$LINE"
cat
) | "$@"
else
exit 0
fi
スクリプトwaituntil
を呼び出して実行可能にしたり、PATH
に入れたりする場合は、次のように使用します
commandA... | waituntil commandB...
例
( sleep 3 ; date ; id ) | waituntil nl