web-dev-qa-db-ja.com

bashのすべてのファイル記述子を閉じる

事前に明示的なリストを用意せずに、開いているすべてのファイル記述子を閉じる方法はありますか?

11
Lorenzo Pistone

文字通りに答えるために、bashall開いているファイル記述子を閉じるには:

for fd in $(ls /proc/$$/fd); do
  eval "exec $fd>&-"
done

ただし、シェルが入力および出力に必要とする基本的なファイル記述子を閉じるため、これは実際には良い考えではありません。これを行うと、実行するどのプログラムも(ttyデバイスに直接書き込む場合を除いて)端末に出力が表示されません。実際にテストでstdinexec 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-)になります。

14
Graeme

最近のバージョンのBash(4.1以降、2009年以降)では、シェル変数を使用して閉じるファイル記述子を指定できます

for fd in $(ls /proc/$$/fd/); do
    [ $fd -gt 2 ] && exec {fd}<&-
done

この機能はすでにKorn Shellに含まれていました(1993年以降?)が、Bashに登場するまでに少し時間がかかったようです。

5
tetsujin

現在のシェルの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
untore

いいえ。カーネルは一度に1つのFDしか閉じることができず、bashにはFDの「グループコマンド」はありません。

for fd in $(ls -1 /proc/27343/fd); do echo exec $fd">&"-; done

テスト後にecho"を削除します。

これがシェル自体ではなくコマンドを実行する場合は、Nohupを使用できます。

0
Hauke Laging

「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
0
David DG