リダイレクト時に文字列を追加する

リダイレクト時に文字列を追加する

すべての出力をstderrにリダイレクトする場合:

stat file >&2

...コマンドでエラーが発生した場合(ファイルが存在しない場合など)、次のように任意のテキストを先頭に追加するにはどうすればよいですか?

<<MY ARBITRARY TEXT>>: stat: cannot stat 'file': No such file or directory

必要なロジックは次のとおりです。

let res = stat file
if error then output "<<MY ARBITRARY TEXT>>"+error to stderr
else output res to stderr

追加のコンテキスト:stdoutストリームとstderrストリームは常に正しい順序で返されるため、すべてのコマンド出力はstderrにリダイレクトされます。つまり、複数のコマンドが送信され、そのうちの1つがエラーを生成する場合、次のコマンドのstdoutが元のstderrに存在する可能性があります。コマンドを返す前にコマンドを実行してください。これを防ぐために、すべてのコマンドをstderrに統合しましたが、理想的にはエラーを簡単に識別できるようにしたいです。

答え1

長い話を短く: stderr を動的に解析するのは複雑な場合があるので、 stderr を変数に保存し、後で変数の内容を操作して単純化します。

考慮すべき点は、stderr変数をキャプチャしてからnullでないことを確認することです。次の例を考えてみましょう。

$ foo=$(stat /etc/passwd 2>&1  > /dev/tty )
  File: /etc/passwd
  Size: 1710        Blocks: 8          IO Block: 4096   regular file
Device: fd00h/64768d    Inode: 537594      Links: 1
Access: (0644/-rw-r--r--)  Uid: (    0/    root)   Gid: (    0/    root)
Access: 2019-03-08 15:28:10.481688274 -0700
Modify: 2019-03-08 15:28:10.333669255 -0700
Change: 2019-03-08 15:28:10.341670283 -0700
 Birth: -
$ test "x$foo" = "x" && echo "empty"
empty

コマンド置換は$(...)サブシェルを実行し、キャプチャのみをstdout実行するので、コマンド置換を介してstderrをキャプチャできるようにファイル記述子1を2にコピーしたいが、2>&1画面上で通常の出力を表示したいので、その後はstdout制御を指します。ターミナル/dev/tty

さて、実際にstderrを変数としてキャプチャするとどうなりますか?

$ foo=$(stat nonexistent.txt 2>&1  > /dev/tty )
$ test "x$foo" = "x" && echo "empty" || echo "not empty"
not empty
$ printf "<Arbitrary Text>%s\n" "$foo"
<Arbitrary Text>stat: cannot stat 'nonexistent.txt': No such file or directory

ご覧のとおり、キャプチャさstderrれているので、必要に応じて任意のテキストを囲むことができます。変数を使用する主な理由は、標準のシェルメソッド(パイプやコマンドの置換など)がstdoutファイル記述子1で機能するため、動的解析があまり実行できないためですstderr。もちろん、名前付きパイプを使用してリダイレクトできますが、stat foobar.txt 2> /tmp/named_pipe.fifoこの問題はブロックです。パイプに送信された情報は他のプロセスによって消費されるまでバッファリングされるため、シェルスクリプトは中断されます。もちろん、これはバックグラウンドプロセスを開始して処理できますが、IMHOは必要以上に複雑で、実際にはマルチプロセッシングコールに直接アクセスできるPythonなどのプログラミング言語を使用してマルチプロセスを実行する方がはるかに優れています。

stdoutとstderrの両方を別々の変数として扱うには、良い例がありますスタックオーバーフローでは、名前付きパイプといくつかのシェル固有のメソッド/トリックを介してこれを実行できます。

注:testand[は同じコマンドなので、[ "x$foo" = "x" ]より詳細なif-elseステートメントで作成して使用することもできます。

答え2

やりたいことをとても簡単に達成できます。

1)ファイルの出力を復元する必要がある場合foobar

 $ (echo "Arbitrary text" && stat /etc/passwd ) 2>&1 | tee foobar

2)より簡単に言えば、興味のあるすべての内容が次に出力される場合stdout

 $ (echo "Arbitrary text" && stat /etc/passwd ) 2>&1

関連情報