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


12

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


4
すべてのどのファイルディスクリプタ?すべてのプロセスにいくつかのオープンがあります。
ウォーレンヤング14

「開いているすべてのファイル記述子」とは何ですか?0、1、2?それとももっとたくさんありますか?もしそうなら、彼らはどこから来たのですか?
U. Windl

スクリプトが終了すると、ファイル記述子は自動的に閉じませんか?
jarno

回答:


15

文字通りに回答するには、開いているすべてのファイル記述子を閉じますbash

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

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

実際に探しているのは、シェルの基本操作の一部ではないすべてのファイル記述子を閉じることです。これらはの0 stdin、の1、stdoutおよびの2ですstderr。これに加えて、いくつかのシェルは他のファイル記述子をデフォルトで開いているようにも見えます。bashたとえば、255(また、端末I / Oのため)とを持っているdashと私は10ポイント/dev/ttyではなく、特定のよりtty/ ptsデバイス端末が使用しています。で0、1、2、255以外のすべてを閉じるにはbash

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の代替で利用できない場合、ドロップされ$(ls /proc/$$/fd)使用は、lsof(それが利用可能な場合)であろう$(lsof -p $$ -Ff | grep f[0-9] | cut -c 2-)


/procLinuxでのみ使用できます。
chepner 2014

4
@chepnerあなたがそれ/proc/PID/fdはあまり移植性がないと言ったらあなたは正しいでしょう。しかし、それ/procがLinuxでのみ利用可能であると言うことは正しい説明ではありません
Graeme 14

一部のWebサイトはこの<&-フォームを使用していますが、必要なものは異なりますか?
Lorenzo Pistone 2014

@LorenzoPistoneの場合、記述子を閉じるときに方向が変化しないため、どちらの形式も使用できます。
Graeme

5

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

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

この機能はすでにKornシェルに含まれていましたが(1993年以降?)、Bashに移行するまでに時間がかかったようです。


1

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

0

「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

しかし、これですべてのファイル記述子が閉じられるわけではありません。
G-Manは 'Reinstate Monica'を

確かに。前の返信で説明したように、ループで実行する必要があります...ここでは「評価」は必須ではなく、同じロジックを保持して開くよりも閉じることができるということを指摘するだけでした。
David DG

0

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

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

削除echoおよび"テストした後。

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


2
が使用するファイル記述子を>&-パラメータにすることはできません。リダイレクトは、パラメーター展開の前に解析されます。
chepner 2014

1
@chepnerは最近exec {fd}>&-動作します。
jarno
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.