パイプを使用せずに標準出力を端末とファイルにリダイレクトしますか?

パイプを使用せずに標準出力を端末とファイルにリダイレクトしますか?

次のコードがあります。

#!/bin/bash

VAR=0

func() {
    VAR=$((VAR+1))
    echo 'Logging information.'
}

func 2>&1 | tee 'log.txt'

echo "Should be 1: ${VAR}"

呼び出されると、次のことが発生します。

:~$ ./script.sh
Should be 1: 0

私が理解したのは、私が使用しているパイプラインがサブシェルを生成するためです。 in への変更はVAR上向きに伝播されないため、出力に反映されません。

func私の場合、プロセスはやや長く、出力はリアルタイムで行わなければなりませんでした。したがって、ファイルに書き込んでからcatそのファイルを読むことはオプションではありません。また、可能であればファイルに何も書かずに変数で読み直すことを避けたいと思います。

それでは、パイプの必要性を満たす方法はありますか?それとも私がまだ知らないのに役立つbashトリックはありますか?

編集する:

名前付きパイプを試してください。

#!/bin/bash

VAR=0

func() {
        VAR=$((VAR+1))
        echo 'Logging information.'
        sleep 5
}

mkfifo my_fifo

func >my_fifo 2>&1 &

tee 'log .txt' <my_fifo

echo "Should be 1: ${VAR}"

残念ながら、結果は同じです。

:~$ ./script.sh
Should be 1: 0

答え1

次のことができます。

func > >(tee log.txt) 2>&1
wait

ロギング専用のファイル記述子を指定できます。

exec 3> >(tee log.txt)
tee_pid=$!

func >&3 2>&1
...

ただし、teeバックグラウンドで実行されるため、すべての出力が通過しないと、出力順序が影響を受ける可能性があります。

答え2

TMPファイルが利用可能

func >tmpfile 2>&1
tee 'log.txt' <tmpfile

または先入れ先出し

mkfifo pipe_replacement
tee 'log.txt' <pipe_replacement &
func >pipe_replacement 2>&1

答え3

私はこれをします...

#!/bin/sh -x
run() if ! ps -p "$run" >&2
      then n=0 run=$$ exec "$0" "$@" 2>&1 | {
         ! tee outfile ; }
      fi 2>/dev/null
run "$@" || exit

fn() { var=val$n; echo "$((n+=1)): $var"; }
fn 
sleep 5
fn
IN

まず、他のプロセスのパイプを開いていることを確認してくださいtee。そうでない場合は、execプロセス自体に入ります。その後、すべての出力はスクリプトの残りの部分にパイプされ、その間に設定されたすべての変数とスクリプト終了が保持されます。実際にこれが最初から確認される方法です。

したがって、上記の印刷を実行してください。

+ run
+ run
+ fn
+ var=val0
+ echo 1: val0
1: val0
+ sleep 5
+ fn
+ var=val1
+ echo 2: val1
2: val1
+ exit

その後、印刷を実行しますcat outfile...

+ run
+ run
+ fn
+ var=val0
+ echo 1: val0
1: val0
+ sleep 5
+ fn
+ var=val1
+ echo 2: val1
2: val1
+ exit

パフォーマンスが高い場合でも、代わりsedに使用することを検討することもできますteeteeフル出力この場合、sed複数のファイルを同時に書き込むことができ、条件に応じて実行できます。

たとえば、次の行をエコーできます。

echo 'LOG-ONLY: some message here'

リスニングsedプロセスは次のことができます。

sed -n '/^LOG-ONLY:/!p;s///w ./my_log.txt'

...w部分を削除した後、ファイルに行を書き込んでLOG_ONLY端末に印刷するのを防ぎます。

関連情報