Закрийте всі дескриптори файлів у bash


13

Чи є спосіб закрити всі дескриптори відкритого файлу, не маючи попереднього явного списку?


4
Все яких файл дескриптори? Кожен процес має деякі відкриті.
Варрен Янг

Що таке "усі відкриті дескриптори файлів"? 0, 1 і 2? Або у вас є багато більше? Якщо так, звідки вони взялися?
U. Windl

Чи не дескриптори файлів закриваються автоматично, коли сценарій закінчується?
jarno

Відповіді:


15

Щоб відповісти буквально, закрити всі відкриті дескриптори файлів для bash:

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

Однак це насправді не є хорошою ідеєю, оскільки вона закриє основні дескриптори файлів, необхідні оболонці для введення та виводу. Якщо ви це зробите, жодна із запущених програм не відображатиметься на терміналі (якщо вони не записуються ttyбезпосередньо на пристрій). Якщо факт у моїх тестах закриття stdin( exec 0>&-) просто призводить до виходу інтерактивної оболонки.

Те, що ви насправді хочете зробити, це скоріше закрити всі дескриптори файлів, які не є частиною базової операції оболонки. Це 0 за stdin, 1 за stdoutі 2 за stderr. Крім цього, деякі оболонки також за замовчуванням мають інші дескриптори файлів. В bash, наприклад, у Вас є 255 (також для терміналу введення / виведення) і 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-).


/procдоступний лише під Linux.
чепнер

4
@chepner ви б мали рацію, якби сказали, що /proc/PID/fdце не дуже портативно. Але твердження, що /procдоступне лише під Linux, не є правильним твердженням.
Graeme

Деякі веб-сайти використовують <&-форму, чи є вона різною / потрібною?
Лоренцо Пістоне

@LorenzoPistone, напрямок не має різниці при закритті дескриптора, тому можна використовувати будь-яку форму.
Graeme

5

В останніх версіях Bash (4.1 і далі, рік 2009 і пізніші) ви можете вказати дескриптор файлу для закриття за допомогою змінної оболонки:

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

Ця функція була в оболонці Корна (з 1993 року?), Але, мабуть, знадобилося певний час, щоб пробитися до Баша.


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 каже: "Відновіть Моніку"

Справді. Вам доведеться виконувати цикл, як це було пояснено у попередніх відповідях ... Просто було вказати на те, що "eval" тут не є обов'язковим, і що ми можемо зберегти ту саму логіку, щоб закрити його, ніж відкрити .. Сторінки людини справді не зрозумілі з цього приводу ...
Девід ДГ

0

Ні. Ядро може закривати лише один FD одночасно, і bash не має "групових команд" для FD.

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

Видаліть echoі "після тестування.

Якщо це не сама оболонка, а команда, яку слід запустити, ви можете використовувати nohup.


2
Дескриптор файлу, яким користується, >&-не може бути параметром; перенаправлення аналізується перед розширенням параметра.
чепнер

1
@chepner сьогодні exec {fd}>&-працює.
jarno
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.