別のコマンドにパイプする前にコマンド出力を完全にバッファリングしますか?


10

一時ファイルなしでコマンドが実行された後にのみコマンドを実行する方法はありますか?もう1つの実行中のコマンドと、出力をフォーマットしてcurlを使用してHTTPサーバーに送信する別のコマンドがあります。実行するとcommandA | commandBcommandBが起動curlし、サーバーに接続してデータの送信を開始します。のでcommandAとても時間がかかり、HTTPサーバがタイムアウトになります。やりたいことができるcommandA > /tmp/file && commandB </tmp/file && rm -f /tmp/file

好奇心から、一時ファイルなしでそれを行う方法があるかどうか知りたいです。試してみましたmbuffer -m 20M -q -P 100が、カール工程はまだ始まったばかりです。Mbuffer commandAは、実際にデータを送信する処理が完了するまで待機します。(データ自体は最大で数百kbです)


どうcommandA && commandBですか?
eyoung100 2015年

1
それはcommandAto の出力を送信しませんcommandBか?
ジョセフは、

コマンドAが正常に完了すると、コマンドBが開始されます。これは、curlが早く開始されないことを意味します。
eyoung100 2015年

2
@ eyoung100しかし、それはcommandAからstdoutをcommandBのstdinに渡しません。これがJosefに必要なものです!
roaima 2015年

出力を渡したい場合は、ファイルを使用する必要があります。cuonglmの答えを見てください。
eyoung100 2015年

回答:


14

これは他のいくつかの回答と似ています。「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; } からの出力の最初の行を読み取りますspongecommandA完了するまで、これは表示されません。  そして、それはアップ発火commandB、パイプへの最初の行を書き込み、呼び出しcat出力の残りの部分を読んで、パイプに書き込み。


ありがとう!sponge私が使っmbufferていたものもそうですが、こちらのほうが適しているようです。ここでは、readを使用するのが賢明です。間違いなくこれは将来のために覚えています。
ジョセフ氏は、2015

@Josef:今まで聞いたことがありませんmbuffer。実際にはと同じくらい良いかもしれませんsponge。使用readは巧妙なトリックであることに同意します。私はそれを完全に信用することはできません。Stack Exchange(U&L、スーパーユーザー、Ask Ubuntuなど)全体の回答に時々表示されます。実際、この質問に対するroaimaの回答は、使用しないsponge(または同等のもの)以外は私のものと非常に似ています。そのため、コメントで述べたように、commandB必要なだけ開始を遅らせません(あなたの問題)。
G-Manは「Reinstate Monica」を

github.com/ildar-shaimordanov/perl-utils#spongeには、bash関数にラップされた「スポンジ」のスクリプトバージョンがあります。
マリナラ

5

パイプラインのコマンドは同時に開始さcommandAれます。後で使用するために出力をどこかに保存する必要があります。変数を使用すると、一時ファイルを回避できます。

output=$(command A; echo A)
printf '%s' "${output%%A}" | commandB

echo Aプロセス内置換の目的は何ですか?
デジタルトラウマ2015年

3
@DigitalTrauma:コマンドの置換によって末尾の改行が削除されるのを防ぎます。
cuonglm 2015年

ああ、なるほど。そうです。コーナーケースの可能性を十分
Digital Trauma

答えが間違っていたので削除しました。代わりにこれは正しいと思います。+1
デジタルトラウマ2015年

どうもありがとう!それは素晴らしく、特にエコーA / %% Aは、改行を維持するために必要です(たとえ私が必要としなくても)
ジョセフは、モニカを

1

この問題に対処できる標準的なUNIXユーティリティは知りません。1つのオプションは、次のように、出力awkを累積commandAcommandB、一度にフラッシュするために使用されます。

commandA  | awk '{x = x ORS $0}; END{printf "%s", x | "commandB"}'

awkは入力から文字列を構築するため、これはメモリを大量に消費する可能性があることに注意してください。


1
これにより、最後の改行が削除されます。最後の文字改行であると仮定すると、最後にa \nまたは別の文字必要ORSです。
G-Manは 'Reinstate Monica'

0

小さなスクリプトで要件を解決できます。この特定の亜種は、追加のプロセスを犠牲にして、一時ファイルと潜在的なメモリ占有を回避します。

#!/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

1
これは、出力の最初のが書き込まcommandBれるまで開始を遅らせるだけです。それはおそらく十分ではありません。commandA
G-Manが「Reinstate Monica」を

@ G-Manがわかりません。私はあなたが好きspongeです。オフにして、今それを読んでください。
roaima 2015年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.