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


11

Есть ли способ закрыть все дескрипторы открытого файла, не имея заранее явного списка их?


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

Что такое "все дескрипторы открытого файла"? 0, 1 и 2? Или у тебя еще много? Если да, то откуда они взялись?
У. Виндл

Разве файловые дескрипторы не закрываются автоматически после завершения работы скрипта?
Ярно

Ответы:


14

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

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

Однако это действительно не очень хорошая идея, поскольку она закроет основные файловые дескрипторы, необходимые оболочке для ввода и вывода. Если вы сделаете это, ни у одной из запущенных вами программ не будет отображаться вывод на терминале (если только они не пишут на ttyустройство напрямую). Если факт в моих тестах close 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.
chepner

4
@chepner вы были бы правы, если бы сказали, что /proc/PID/fdэто не очень удобно. Но говорить, что /procдоступно только под Linux, не является правильным утверждением.
Грэм

Некоторые веб-сайты используют <&-форму, она отличается от других / нужна?
Лоренцо Пистоне

@LorenzoPistone, направление не имеет значения при закрытии дескриптора, поэтому можно использовать любую форму.
Грэм

5

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

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

Эта функция уже была в оболочке Korn (с 1993 года?), Но, видимо, потребовалось некоторое время, чтобы проникнуть в Bash.


1

Очистить все файловые дескрипторы, кроме ввода / вывода текущей оболочки, но также исключить те, которые представлены в качестве аргументов

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
Используемый дескриптором файла >&-не может быть параметром; перенаправление анализируется перед расширением параметра.
chepner

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