与えられたシェルスクリプト:
#!/bin/sh
echo "I'm stdout";
echo "I'm stderr" >&2;
コマンドの最後の部分が2>/dev/nullの場合、stderrのみが出力されるように、そのスクリプトを呼び出す方法はありますか。
$ > sh myscript.sh SOME_OPTIONS_HERE 2>/dev/null
I'm stderr
または、代わりに:
$ > sh myscript.sh SOME_OPTIONS_HERE >/dev/null
I'm stdout
一連の講義スライドの最後にある質問ですが、これで1日近く働いた後、それはある種のタイプミスであるとほぼ確信しています。ピボットは機能しません。 2>&-は機能しません。私はアイデアがありません!
% (sh myscript.sh 3>&2 2>&1 1>&3) 2>/dev/null
I'm stderr
% (sh myscript.sh 3>&2 2>&1 1>&3) >/dev/null
I'm stdout
3>&2 2>&1 1>&3
の説明:
3>&2
は、fd 3(ファイル記述子3)という名前のファイル記述子2(fd 2)(stderr)のコピーを作成を意味します。 ファイル記述子をコピーします、tee
のようにストリームを複製しません。2>&1
は、sh myscript.sh
のfd2がそのfd1(stdout)のコピーになることを意味します。これで、myscriptがstderr(fd 2)に書き込むと、stdout(fd 1)で受信します。1>&3
は、sh myscript.sh
のfd1がfd3(stderr)のコピーになることを意味します。これで、myscriptがstdout(fd 1)に書き込むと、stderr(fd 2)で受信します。完全を期すために、上記の@ 200_successによるコメントに基づいて、1>&3-
を使用してファイル記述子3を move する方がおそらく良いでしょう。
$ (sh myscript.sh 3>&2 2>&1 1>&3-) 2>/dev/null
I'm stderr
$ (sh myscript.sh 3>&2 2>&1 1>&3-) >/dev/null
I'm stdout
プロセスごとにファイル記述子を交換する代わりに、exec
を使用して、現在のシェルによって起動された次のすべてのコマンドのstdinとstderrを交換できます。
$ (exec 3>&2 2>&1 1>&3- ; sh myscript.sh ; sh myscript.sh ) 2>/dev/null
I'm stderr
I'm stderr
$ (exec 3>&2 2>&1 1>&3- ; sh myscript.sh ; sh myscript.sh ) >/dev/null
I'm stdout
I'm stdout
ファイル記述子の移動(1>&3-
)は移植性がなく、すべてのPOSIXシェル実装がそれをサポートしているわけではありません。それはksh93-ismとbash-ismです。 (詳細はこちら https://unix.stackexchange.com/questions/65000/practical-use-for-moving-file-descriptors )
リダイレクトを実行した後、代わりにFD3を閉じることもできます。
ls 3>&2 2>&1 1>&3 3>&-
現在の作業ディレクトリの内容をstderrから出力します。
構文3>&-
または3<&-
ファイル記述子3を閉じます。
bash hackers wiki は、この種のことで非常に役立ちます。これらの答えの中で言及されていないそれを行う方法があるので、私は私の2セントを入れます。
数値Nの>&N
のセマンティクスは、ファイル記述子Nのtargetにリダイレクトするを意味します。記述子は後でターゲットを変更できるため、Wordtargetは重要ですが、そのターゲットをコピーした後は気にしません。これが、リダイレクトを宣言する順序が適切である理由です。
したがって、次のように実行できます。
./myscript.sh 2>&1 >/dev/null
つまり、次のことを意味します。
stderrをstdoutのターゲット、つまりstdout出力ストリームにリダイレクトします。 stderrがstdoutのターゲットをコピーしました
stdoutを/ dev/nullに変更します。変更する前にターゲットを「コピー」したため、これはstderrには影響しません。
3番目のファイル記述子は必要ありません。
>&-
の代わりに>/dev/null
を単純に実行できないのは興味深いことです。これは実際にはstdoutを閉じるので、エラーが発生します(stderrのターゲットでは、もちろん実際のstdoutです:D)
line 3: echo: write error: Bad file descriptor
リダイレクトを交換しようとすると、順序が関連していることがわかります。
./myscript.sh >/dev/null 2>&1
これは機能しません。理由は次のとおりです。
/dev/null
に設定しました/dev/null
に設定しました。