teeを使用してコードブロックのSTDOUTをブロック内で定義されたファイル名でキャプチャする方法は?

teeを使用してコードブロックのSTDOUTをブロック内で定義されたファイル名でキャプチャする方法は?

送りたい標準出力ファイルのスクリプトブロックの場合、その名前はブロック内の変数によって定義されます。しかし、私が使うときティー、ブロック外の変数がもう存在しないようです。いいえティー、変数がまだ存在します。

スクリプト:

#!/bin/bash
{
    log="mylog.txt"
    echo log: $log
} |tee $log

echo log: $log

結果:

log: mylog.txt
log:

そしてではない私のログ.txt生成されたファイルティー

答え1

 #!/bin/bash
 log="mylog.txt"
 {
     echo log: $log
 } |tee $log

パイプは、コマンドのリストがサブシェルで実行されるようにします。変数が別のサブシェルにあるため、上に渡すことはできません。したがって、変数を正しく使用するには、変数をパブリックコンテキストに移動する必要があります。

答え2

名前付きパイプが役に立ちます。もう少し作業すれば、trap後でファイルシステムのクリーンアップを処理するために設定や同様の作業を行わずに強力に取得できます。事前に行うだけです。

pipe=/tmp/$$pipe log=mylog.txt
mkfifo "$pipe"; exec 3<>"$pipe"
{ rm "$pipe"; tee "$log"; } <&3 >/dev/tty &
pipe=$!; exec >&3 3>&-

そこに。この時点から、すべてのスクリプトの出力は次の場所に書き込まれます。(以前)teeバックグラウンドプロセスで読んでいる名前付きパイプ。名前付きパイプの特殊ファイルはファイルシステムから削除されたため、後でクリーンアップする必要はありません。残りの唯一の参照は、スクリプトのstdoutsumに割り当てられたteeファイル記述子ですstdin

つまり、少なくとも1つを設定するのが賢明かもしれませんtrap

trap "kill PIPE $pipe" 0

tee...スクリプトが終了した後にバックグラウンドで中断されないようにするためです。

teeバッファリングの問題がある場合(公開回線があるため問題にならないようです)、/dev/tty電話をかけて運を試してみることができます。このページは、特に懸念される部分のリスクを防止します。つまり、アプリケーションが呼び出し後に独自のバッファのサイズを変更できることに言及していますが、相互作用については実際よりも肯定的です。teestdbufstdbufmanteeteedd

関連情報