1

なぜこれが機能しないのですか?

私の見方では、fd 3を開いて、devnulに送信します。

その後、ルートfd3からfd2になります。

私が達成しようとしているのは、スクリプトでfd 3を標準情報として使用することです。これは、デフォルトでvoidにパイプされますが、必要に応じてstderrまたは検査用のファイルにルーティングできます。

MyScript.bash

exec 3>/dev/null
echo spo >&3

これはstderrに何もエコーしません:

./MyScript.bash 3>&2
4

1 に答える 1

1

スクリプトを実行すると、シェルはファイル記述子 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
于 2013-03-10T09:03:14.777 に答える