事前に明示的なリストを用意せずに、開いているすべてのファイル記述子を閉じる方法はありますか?
文字通りに答えるために、bash
のall開いているファイル記述子を閉じるには:
for fd in $(ls /proc/$$/fd); do
eval "exec $fd>&-"
done
ただし、シェルが入力および出力に必要とする基本的なファイル記述子を閉じるため、これは実際には良い考えではありません。これを行うと、実行するどのプログラムも(tty
デバイスに直接書き込む場合を除いて)端末に出力が表示されません。実際にテストでstdin
(exec 0>&-
)を閉じると、対話型シェルが終了します。
実際に実行する必要があるのは、シェルの基本操作の一部ではないすべてのファイル記述子を閉じることです。これらは、stdin
の場合は0、stdout
の場合は1、stderr
の場合は2です。これに加えて、いくつかのシェルは他のファイル記述子をデフォルトで開いているようにも見えます。たとえば、bash
には255(端末I/Oの場合も)があり、dash
には10あります。これは、端末が使用している特定のtty
/pts
デバイスではなく/dev/tty
を指します。 bash
の0、1、2、255以外のすべてを閉じるには:
for fd in $(ls /proc/$$/fd); do
case "$fd" in
0|1|2|255)
;;
*)
eval "exec $fd>&-"
;;
esac
done
変数に含まれているファイル記述子をリダイレクトする場合、eval
が必要です。そうでない場合、bash
は変数を拡張しますが、コマンドの一部と見なします(この場合、exec
コマンド0
または1
またはファイル記述子のいずれかを試みます。閉じようとしています)。
注:また、ls
の代わりにグロブを使用すると(たとえば、/proc/$$/fd/*
)、グロブの追加のファイル記述子が開かれるように見えるため、ls
が最善の解決策のようです。
/proc/$$/fd
の移植性の詳細については、 ファイル記述子リンクの移植性 を参照してください。 /proc/$$/fd
が利用できない場合、lsof
(利用可能な場合)を使用して$(ls /proc/$$/fd)
を置き換えると、$(lsof -p $$ -Ff | grep f[0-9] | cut -c 2-)
になります。
最近のバージョンのBash(4.1以降、2009年以降)では、シェル変数を使用して閉じるファイル記述子を指定できます。
for fd in $(ls /proc/$$/fd/); do
[ $fd -gt 2 ] && exec {fd}<&-
done
この機能はすでにKorn Shellに含まれていました(1993年以降?)が、Bashに登場するまでに少し時間がかかったようです。
現在のシェルのi/o/eを除くすべてのファイル記述子をクリアしますが、引数として提供されたものも除外します
clear_fds() {
for fd in $(compgen -G "/proc/$BASHPID/fd/*"); do
fd=${fd/*\/}
if [[ ! " $* " =~ " ${fd} " ]]; then
case "$fd" in
0|1|2|255)
;;
*)
eval "exec $fd>&-"
;;
esac
fi
done
}
いいえ。カーネルは一度に1つのFDしか閉じることができず、bashにはFDの「グループコマンド」はありません。
for fd in $(ls -1 /proc/27343/fd); do echo exec $fd">&"-; done
テスト後にecho
と"
を削除します。
これがシェル自体ではなくコマンドを実行する場合は、Nohup
を使用できます。
「eval」をまったく使用しない別の方法は、次の形式を使用することです。
$ exec {var_a}>> file.txt
$ echo $var_a
10
$ ls -l /proc/self/fd/10
l-wx------ 1 0 0 64 Dec 11 18:32 /proc/self/fd/10 -> /run/user/0/tmp/file.txt
$ echo "aaaaa" >&$var_a
$ cat file.txt
aaaaa
$ exec {var_a}>&-
$ ls /proc/self/fd/10
ls: cannot access '/proc/self/fd/10': No such file or directory