次のスクリプトが与えられたら、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
これがリダイレクトされたファイルを切り捨てる理由をまだ理解していません。