スクリプト内のtee /dev/stderrは、stderrがリダイレクトされると出力ファイルを切り捨てます。

スクリプト内のtee /dev/stderrは、stderrがリダイレクトされると出力ファイルを切り捨てます。

次のスクリプトが与えられたら、stderrをファイルにリダイレクトしようとすると、ファイルが使用されたteeときに切り捨てられます。

$ cat test.sh 
#!/bin/bash

set -eux
echo before
echo '{ "foo": "bar" }' | tee /dev/stderr | jq .foo
echo after
$ ./test.sh 2> log
before
"bar"
after
$ cat log 
{ "foo": "bar" }
+ echo after

このlogファイルにはすべてのstderr出力を含める必要があります。リダイレクトせずに同じスクリプトを実行すると、次のように表示されます。

$ ./test.sh
+ echo before
before
+ echo '{ "foo": "bar" }'
+ tee /dev/stderr
+ jq .foo
{ "foo": "bar" }
"bar"
+ echo after
after

それでは、なぜ私は現れる行だけを見ることができますか?後ろに tee?使っても2>>あまり役に立たないようです。

なぜこれが起こるのかわかりません。スクリプト全体の標準エラーをファイルにリダイレクトする機能を維持しながら出力を取得するにはどうすればよいですか?

答え1

これはLinuxで動作する方法によるもの/dev/stderrです/proc/$pid/fd/$num。ああ、/dev/stderr本当に開いていいえファイル記述子2を繰り返して、代わりにfdで直接接続されたリソースにアクセスします。

したがって、tee一般的に書き込むファイルを切り捨てるのでtee /dev/stderr。あなたの場合これはtee log

バラよりvar=$(</dev/stdin) stdin を変数として読み込む際にどのような問題がありますか?もっと学ぶ。


これはLinuxでのみ発生する問題です。たとえば、macOSでは想像通りに動作します。やや圧縮された例:

linux$ bash -xc 'false; echo "truncated?" | tee /dev/stderr >/dev/null; true' 2>log
linux$ cat log
truncated?
+ true

〜に向かって

mac$ bash -xc 'false; echo "truncated?" | tee /dev/stderr >/dev/null; true' 2>log
mac$ cat log
+ false
+ tee /dev/stderr
+ echo 'truncated?'
truncated?
+ true

これがうまくいくには、それを使用するのを避け、/dev/stderr代わりに>&2シェルにファイル記述子2をコピーするように指示するようなものを使用する必要があります。

私はあなたがこれを行うことができると思いますtee >( cat >&2 )。これは少し複雑ですが、tee既存のfdを使用するように言うことはできません。ファイル名上記の問題のため、スクリプトのstderrを直接参照することはできません。

catただし、以下のようにバックグラウンドで実行されるため、出力が遅れる可能性があるという問題があります。

linux$ bash -xc 'false; echo "truncated?" | tee >(cat >&2) >/dev/null; true' 2>log
$ cat log
+ false
+ echo 'truncated?'
+ tee /dev/fd/63
++ cat
+ true
truncated?

これは、すべての書き込みがファイルの末尾に移動することをtee -a /dev/stderr意味しますが、生のstderrを介して書かれたものはすべて役に立たないことに注意してください。teeいいえただし、ファイルに記載されている書き込み位置に従います。だからあなたは次のようなものを得るでしょう:

$ bash -xc 'false; echo "truncated?" | tee -a /dev/stderr >/dev/null; true' 2>log
$ cat log
+ false
+ echo 'truncated?'
+ tee -a /dev/stderr
+ true
ed?

最後のエントリ+ true<nl>(スクリプトのstderr)はtruncated?(from tee)に書き込まれます。また、元のリダイレクトを追加さ​​れたリダイレクト(たとえば)にする必要がありますbash ... 2>>log

あるいは、ソースをファイルの代わりにパイプにリダイレクトするだけです。パイプを使用すると、/dev/stderrパイプに書き込み位置がなく、切り捨てられないため、想像するのと同じように機能します。ただし、その方法が少し複雑なので、そのようなものが必要なだけです2> >(cat > log)

答え2

この記事を書いて、私はこのtee -aオプションが私にとっても可能であることに気づきました。

tee /dev/stderrこれがリダイレクトされたファイルを切り捨てる理由をまだ理解していません。

関連情報