頑張っていますラッパースクリプトcronjob 出力を記録します。
私はいくつかの目標を持っています:
- stderrとstdoutは、異なる優先順位とプレフィックスラベルを使用して記録する必要があります。
- また、ラップされたコマンドのstderrをラッパースクリプトのstderrに出力する必要があります(cronでキャプチャして電子メールで警告します)。
- 行の順序は常に維持する必要があります
これまでに2つの問題があるようです。
- stderrとstdoutを別々にロギング機能にリダイレクトする方法がわかりません。これまで試したことはすべて、NULL以外をリダイレクトできませんでした。私の考えでは、リダイレクトは私の利点の1つではありません。(解決済み、コメントを参照)
- 私の現在のアプローチ
{ $_EXEC $_ARGS 2>&1 1>&7 7>&- | journaldlog error; } 7>&1 1>&2 | journaldlog info
は、ロギング機能を2回(stderrに対して1回、stdoutに対して1回)実行するようです。これにより、行の順序は維持されません。むしろ、出力ラインごとに一度だけ関数を実行したいと思います。
bashでこれを放棄し、Perlを試すべきですか?私はPerlの経験が最終的に戻ってくると確信しています。
私は様々なことを試しました。これらのほとんどはオンライン、特にStack Exchangeで見つけることができます。私は正直、私が何をしようとしたのか覚えていません。この時点では、ぼやけているだけです。そしてbashドキュメントはあまり役に立ちません。
答え1
ただ使えますプロセスの交換リダイレクトから直接:
gen > >(one) 2> >(two)
これにより、標準出力がgen
標準入力として提供され、one
標準エラーがgen
入力として提供されますtwo
。実行可能なコマンドまたは関数にすることができます。私が使用する機能は次のとおりです。
one() {
while read line
do
echo $'\e[31m'"$line"$'\e[22m'
done
}
two() {
while read line
do
echo $'\e[32m'"$line"$'\e[22m'
echo "$line" >&2
done
}
入力ラインをそれぞれ赤と緑に出力し、two
通常の標準エラーにも記録します。ループ内で必要なものは何でもでき、入力を他のプログラムや必要なものに送信できます。
気づくこの時点まで、「行順の維持」などの実用的な機能はありません。- 2つの独立したストリームと独立したプロセス。スケジューラはしばらくの間プロセスを実行し、別のプロセスを実行し、データは読み取られるまでカーネルパイプバッファに保持されます。私はテストのために奇数をstdoutとstderrに出力する関数を使用してきました。
端末に表示されているものに近い注文を取得できますが、Bashの注文ではない可能性があります。交換プログラムの使い方pipe
そしてselect
シーケンスを再構成することは可能です(表示されているものと同じであることを保証することはできませんが、同じ理由でプロセスがしばらくスケジュールされない可能性があり、バックログが発生すると最初に何が起こったかを知る方法はありません1 )。。順序が重要な場合は、他のアプローチが必要であり、基本実行可能ファイルの共同作業も必要になる場合があります。これが難しい要件であれば、在庫してみることをお勧めします。
1パイプバッファリングを制御するプラットフォーム固有の方法があるかもしれませんが、この方法も十分に役に立ちません。 Linuxでは、バッファサイズをシステムページサイズに減らすことができますが、それを下げることはできません。私はすぐに書き込みを強制できる(または読むまでブロックできる)機能を知りません。それにもかかわらず、ソースからstdioストリームにバッファリングされる可能性が高いため、ソートは表示されません。
答え2
これは、stderrとstdoutをそれぞれ関数にリダイレクトするために使用する方法です。
tag() { awk '$0="['$1'] "$0; fflush();' ; }
{
{
echo std1; sleep 0.1;
echo error2 >&2; sleep 0.1;
echo error3 >&2; sleep 0.1;
echo std4; sleep 0.1;
} 2>&1 1>&3 | tag STDERR 1>&2 ;
} 3>&1 | tag STDOUT 3>&- ;
これにより、次の出力が提供されます。
[STDOUT] std1
[STDERR] error2
[STDERR] error3
[STDOUT] std4
私のbashとksh(93u +)で動作します。
この場合、行の順序が維持されるように、コマンド間に「sleep 0.1」を追加しました。
答え3
キャプチャする方法です。標準出力そして標準エラー別のコマンドパイプラインで。
#!/bin/bash
#
exec 3>&1 4>&2
loggerForStdout() {
# FD 3 is the original stdout
local x
while IFS= read -r x; do printf "STDOUT\t%s\n" "$x"; done >&3
}
loggerForStderr() {
# FD 4 is the original stderr
local x
while IFS= read -r x; do printf "STDERR\t%s\n" "$x"; done >&4
}
( (
# This is where your command would be put
# e.g. stdbuf -oL -eL rsync -a /from /to
#
echo this is stdout; echo this is stderr >&2
) | loggerForStdout ) 2>&1 | loggerForStderr
を使用してもわかりませんstdbuf -oL -eL
。
代替ロガーがある場合は、最初の3行を省略できます。これはコードを完全かつ独立した例にするためにのみ存在します。