Tutup semua deskriptor file di bash

12

Apakah ada cara untuk menutup semua deskriptor file terbuka, tanpa memiliki daftar eksplisit sebelumnya?

Lorenzo Pistone
sumber
4
Semua deskriptor file yang mana ? Setiap proses memiliki beberapa yang terbuka.
Warren Young
Apa itu "semua deskriptor file terbuka"? 0, 1, dan 2? Atau apakah Anda memiliki lebih banyak? Jika demikian, dari mana asalnya?
U. Windl
Bukankah deskriptor file ditutup secara otomatis saat skrip selesai?
jarno

Jawaban:

15

Untuk menjawab secara harfiah, untuk menutup semua deskriptor file terbuka untuk bash:

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

Namun ini sebenarnya bukan ide yang baik karena akan menutup deskriptor file dasar yang dibutuhkan oleh input dan output. Jika Anda melakukan ini, tidak ada program yang Anda jalankan akan menampilkan hasilnya di terminal (kecuali jika mereka langsung menulis ke ttyperangkat). Jika kenyataannya dalam tes saya menutup stdin( exec 0>&-) hanya menyebabkan shell interaktif untuk keluar.

Apa yang sebenarnya ingin Anda lakukan adalah menutup semua deskriptor file yang bukan bagian dari operasi dasar shell. Ini adalah 0 untuk stdin, 1 untuk stdoutdan 2 untuk stderr. Selain itu, beberapa shell juga tampaknya memiliki deskriptor file lain yang terbuka secara default. Di bash, misalnya, Anda memiliki 255 (juga untuk terminal I / O) dan di dashI memiliki 10, yang mengarah ke /dev/ttydaripada spesifik tty/ ptsperangkat yang digunakan terminal. Untuk menutup semuanya kecuali 0, 1, 2 dan 255 di bash:

for fd in $(ls /proc/$$/fd); do
  case "$fd" in
    0|1|2|255)
      ;;
    *)
      eval "exec $fd>&-"
      ;;
  esac
done

Perhatikan juga bahwa evaldiperlukan ketika mengarahkan kembali deskriptor file yang terdapat dalam variabel, jika tidak bashakan memperluas variabel tetapi anggap itu bagian dari perintah (dalam hal ini akan mencoba execperintah 0atau 1atau deskriptor file mana pun yang Anda coba tutup).

CATATAN: Juga menggunakan glob bukannya ls(misalnya /proc/$$/fd/*) tampaknya membuka deskriptor file tambahan untuk glob, jadi lssepertinya solusi terbaik di sini.

Memperbarui

Untuk informasi lebih lanjut tentang portabilitas /proc/$$/fd, silakan lihat Portabilitas tautan deskriptor file . Jika /proc/$$/fdtidak tersedia, maka penggantian untuk $(ls /proc/$$/fd), menggunakan lsof(jika tersedia) akan menjadi $(lsof -p $$ -Ff | grep f[0-9] | cut -c 2-).

Graeme
sumber
/prochanya tersedia di Linux.
chepner
4
@ chepner Anda akan benar jika Anda mengatakan itu /proc/PID/fdtidak terlalu portabel. Tetapi mengatakan bahwa /prochanya tersedia di Linux bukanlah pernyataan yang benar.
Graeme
Beberapa situs web menggunakan <&-formulir, apakah ada bedanya / diperlukan?
Lorenzo Pistone
@LorenzoPistone, arah tidak ada bedanya saat menutup deskriptor, sehingga salah satu formulir dapat digunakan.
Graeme
5

Dalam versi terbaru dari Bash (4.1 dan seterusnya, tahun 2009 dan yang lebih baru), Anda dapat menentukan deskriptor file untuk ditutup menggunakan variabel shell:

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

Fitur itu sudah ada di shell Korn (sejak 1993?) Tetapi tampaknya butuh waktu untuk masuk ke Bash.

tetsujin
sumber
1

Hapus semua deskriptor file kecuali i / o / e dari shell saat ini, tetapi juga mengecualikan yang disediakan sebagai argumen

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
}
belum dibuka
sumber
0

Cara lain tanpa "eval" sama sekali, adalah dengan menggunakan formulir:

$ 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
David DG
sumber
Tapi ini tidak menutup semua deskriptor file.
G-Man Mengatakan 'Reinstate Monica'
Memang. Anda harus mengeksekusi dalam satu lingkaran seperti yang dijelaskan dalam balasan sebelumnya ... Itu hanya untuk menunjukkan fakta bahwa "eval" tidak wajib di sini dan bahwa kita dapat menjaga logika yang sama untuk menutupnya daripada membukanya .. Halaman manual benar-benar tidak jelas tentang ini ...
David DG
0

Tidak. Kernel hanya dapat menutup satu FD pada satu waktu, dan bash tidak memiliki "perintah grup" untuk FD.

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

Hapus echodan "setelah pengujian.

Jika ini bukan untuk shell itu sendiri tetapi untuk menjalankan perintah maka Anda dapat menggunakan nohup.

Hauke ​​Laging
sumber
2
Deskriptor file yang digunakan oleh >&-tidak bisa menjadi parameter; pengalihan diuraikan sebelum ekspansi parameter.
chepner
1
@chepner saat ini exec {fd}>&-berfungsi.
jarno