ここで何が起こっているのか誤解しているかもしれませんが、これがパイプバッファリングに関連しているようです。さまざまなロギングレベルを達成するために複数のファイル記述子(#3以降)を使用するスクリプトがあります。コマンドラインオプションに応じて、それらのいくつかは同じファイルで、いくつかはコンソールで、いくつかは/dev/null
。ファイルの代わりに標準出力に変換します。その理由は、複数のファイル記述子を1つのファイルにリダイレクトしたときに順序が正しくないように到着したことがわかったためです。つまり、私は喜んで
exec >/some/file 3>&1
代わりに
exec >/some/file 3>/some/file
今まではそんなに良くなった。ただし、時にはコマンドのエラー出力を取得してカスタム記述子の1つ(例:3)に送信する必要があります。この記述子はstdoutに送信できます(これはファイルに戻ります)。その後、順序が間違ったメッセージを受け取ります。このコマンドのメッセージは、後続のコマンドのメッセージの後に表示されます。これは小さなPoCです。私は何が間違っていましたか?
#!/bin/bash
check_if_ordered() {
sort -n -k1 -k2 test_out.txt > test_out_sorted.txt
if ! diff test_out.txt test_out_sorted.txt >/dev/null ; then
echo "Oops, messages are NOT in order" >&2
else
echo "Good, messages are in order" >&2
fi
rm test_out.txt test_out_sorted.txt
}
log() {
while read msg; do
echo "$msg"
done
}
foo() {
for i in {1..150} ; do
echo "$1 $i"
done
}
#### This always works OK, but can't use it in my scenario
echo "Redirecting command output to file"
foo "1" > >(log) > test_out.txt
foo "2" > >(log) >> test_out.txt
check_if_ordered
#### This is similar to what I need to do and always fails
echo "Redirecting stdout to file"
exec >test_out.txt
foo "1" > >(log)
foo "2" > >(log)
check_if_ordered
コマンドバッファリングを無効にするための外部ツールを知っていますが、この場合は利用できないことに注意してください(私のスクリプトはできるだけ移植可能であり、さまざまなディストリビューションで実行する必要があります)。
答え1
#### This always works OK, but can't use it in my scenario
foo "1" > >(log) > test_out.txt
foo "2" > >(log) >> test_out.txt
次のリダイレクトはstdoutをファイルに直接リダイレクトすることをオーバーライドするため、ここでプロセスのオーバーライドは重複しているように見えます。つまり、最初のものはと同じでなければなりませんfoo "1" > test_out.txt
。
#### This is similar to what I need to do and always fails
exec >test_out.txt
foo "1" > >(log)
foo "2" > >(log)
ここでの問題は、プロセスの交換が非同期的に実行され、ループが遅いため、2番目のループがwhile read; do echo
開始されたときに最初のループがlog
まだ実行中であり、パイプバッファから読み取られることです。これはecho foo > >(cat; sleep 1; echo hi)
、コマンドラインで同様の操作を実行するのと似ており、次のプロンプトが表示された後に表示されますhi
。また、wait
ここでは役に立たないようです。
log
しかし、なぜ最初に2つのコピーが必要なのかわかりません。このことをする人は一人ではありません。
exec >test_out.txt
exec 9> >(log)
foo "1" >&9
foo "2" >&9
(私のシステムでは、代わりにcat
それを使用すると、より速く、より大きな塊を読むためにwhile read; do echo
問題が隠されますcat
。しかし、それは問題が完全に解決されるという意味ではなく、同じコピー以外の作業をしたい場合があります。)log
。
コマンドバッファリングを無効にできる外部ツールを知っていることに加えてください。
つまり、stdbuf -o0
プロセス内部(Cライブラリ)のバッファリングにのみ役立ちます。ここではうまくいかないようです。シェルは、echo
返す前に実際にオペレーティングシステムにデータを書き込む必要があります。