web-dev-qa-db-ja.com

ファイル記述子が有効かどうかのテスト

Bashスクリプトに、ファイル記述子(FD)が開いているときに、3以上の追加情報を出力させたいと思います。 FDが開いているかどうかをテストするために、次のトリックを考案しました。

if (printf '' 1>&3) 2>&-; then
  # File descriptor 3 is open
else
  # File descriptor 3 is not open
fi

これは私のニーズには十分ですが、FDが有効かどうかをテストするためのより慣用的な方法があるかどうかについて知りたいと思います。 fcntl(1) syscallのシェルコマンドへのマッピングが存在するかどうかに特に興味があります。これにより、FDフラグ(O_WRONLYおよびO_RDWR FDが書き込み可能かどうかをテストし、O_RDONLYおよびO_RDWR FDが読み取り可能かどうかをテストします)。

12
Witiko

ksh(AT&Tとpdkshの両方のバリアント)またはzshでは、次のことができます。

_if print -nu3; then
  echo fd 3 is writeable
fi
_

それらはそのfdには何も書き込みませんが、fdが書き込み可能かどうかを確認し(fcntl(3, F_GETFL)を使用)、それ以外の場合はエラーを報告します。

_$ ksh -c 'print -nu3' 3< /dev/null
ksh: print: -u: 3: fd not open for writing
_

(これは_/dev/null_にリダイレクトできます)。

bashを使用する場合、dup()がアプローチのように成功するかどうかを確認するのが唯一のオプションだと思いますが、fdが書き込み可能であることは保証されません(または外部ユーティリティ(zsh/Perl...)fcntl())を実行します。

bashでは(ほとんどのシェルと同様)、_(...)_ではなく_{...;}_を使用すると、余分なプロセスがフォークされることに注意してください。以下を使用できます。

_if { true >&3; } 2<> /dev/null
_

代わりに、フォークを回避します(複合コマンドをリダイレクトすると常にサブシェルが発生するBourneシェルを除く)。 trueの代わりに_:_を使用しないでください。これはspecial組み込みであるため、bashがPOSIX準拠モードの場合にシェルが終了します。

ただし、次のように短縮できます。

_if { >&3; } 2<> /dev/null
_
12

POSIX commandApplication Usageの説明には、以下が含まれます。

場合によっては、特別なビルトインの特別な特性を抑制することにはいくつかの利点があります。例えば:

command exec > unwritable-file

非インタラクティブスクリプトが異常終了しないので、スクリプトで出力ステータスを確認できます。

これがあなたがただできる理由です:

if    command >&3
then  echo 3 is open >&3
else  ! echo 3 is not open
fi    2<>/dev/null

または...

{ command >&3
  printf %s\\n%.0d  string "0$(($??8:0))" >&"$(($??1:3))"
} 2<>/dev/null

stringの後に\newlineを続けてstdoutまたは3に書き込み、3が開いていない場合でもゼロ以外の終了ステータスを渡します。 $?で行われた数学は、8進数08%decimalですが、8進数00はまったく切り捨てられません。

または...

command exec >&3 || handle_it

ただし、ksh93を使用している場合は、次のようにすることができます。

fds

開いているファイル記述子のリスト。 -lを追加して、彼らの行き先を確認しましょう。

7
mikeserv

あなたのトリックはかわいいですね。しかし、慣用的な方法で、なぜあなたが使用しなかったのか疑問に思います:

if ( exec 1>&3 ) 2>&-
3
Janis

開いているファイル記述子は/proc/<pid>/fdにあります。たとえば、現在のシェルの開いているファイル記述子を一覧表示するには、次のようなls -l /proc/$$/fdを発行できます。

total 0
lrwx------ 1 testuser testuser 64 jun  1 09:11 0 -> /dev/pts/3
lrwx------ 1 testuser testuser 64 jun  1 09:11 1 -> /dev/pts/3
lrwx------ 1 testuser testuser 64 jun  1 09:11 2 -> /dev/pts/3
lrwx------ 1 testuser testuser 64 jun  1 09:39 255 -> /dev/pts/3

次を使用してファイルを開く場合:

touch /tmp/myfile
exec 7</tmp/myfile

新しいls -l /proc/$$/fdでリストされます。

lr-x------ 1 testuser testuser 64 jun  1 09:11 7 -> /tmp/myfile

exec 7>&-を使用して再度ファイル記述子を閉じると、/proc/$$/fdにも表示されなくなります。

3
Lambert