スクリプトを実行すると、シェルはファイル記述子 3 を stderr にアタッチします。
ただし、スクリプト内exec
では、ファイル記述子 3 データをビット バケットに送信するために使用され、スクリプトの実行時に行ったことを基本的にオーバーライドします。
これを回避する 1 つの方法は、スクリプトの開始時にリダイレクトを行わないことです。代わりに、使用するファイルにオプションのパラメーターを渡します。
./MyScript # with no parameter
./MyScript /tmp/xyzzy # with a parameter
次に、スクリプトを完全に制御します。
fd3file=/dev/null
if [[ "$1" != "" ]] ; then
fd3file="$1"
fi
exec 3>${fd3file}
パラメータを使用する必要はありません。環境変数、構成ファイルのエントリなど、任意の情報源を使用できます。ただし、基本的な前提は成り立っています。決定はスクリプトに任せてください。
これで、次の事実を利用して、複数のレイヤー (シェルとスクリプトのリダイレクト) でこれを行うことができます。
- 実際には開いていない出力のファイル記述子を複製しようとすると、リダイレクト エラーと見なされます。と
exec
リダイレクト エラーが発生した場合、リターン コード 1 で失敗します。
次のスクリプトは、これを実際に示しています。fd 3
複製を試み、fd 4
障害を検出します。失敗手段fd 3
は開かれていないので、 に接続し/dev/null
ます。成功は、それが開いていたことを意味し、ユーザーがすでに何かに接続しているため、そのままにしておきます。
#!/bin/bash
# Try and duplicate fd 3 (without ugly error message)
( exec 4>&3 ) 2>/dev/null
# Figure out whether fd3 was open.
if [[ $? -eq 1 ]] ; then
# It was not open so we need redirect.
echo 'redirect failed, need to exec 3>/dev/null'
exec 3>/dev/null
else
# It was, open so we leave fd3 alone (and close fd4 duplicate).
echo 'redirect worked, leave fd3 alone'
exec 4>-
fi
echo 'fd3 content' >&3
次のトランスクリプトは、実際の動作を示しています。まず、スクリプトを次の場所に接続させるシェルベースのリダイレクトのないfd 3
もの/dev/null
:
pax> ./qq.sh
redirect failed, need to exec 3>/dev/null
pax> cat qq
cat: qq: No such file or directory
次に、シェルベースのリダイレクション ( to qq
) がそのまま残っているもので、 へのリダイレクションが発生fd 3
したことがわかります。qq
pax> ./qq.sh 3>qq
redirect worked, leave fd3 alone
pax> cat qq
fd3 content