Есть ли способ закрыть все дескрипторы открытого файла, не имея заранее явного списка их?
Есть ли способ закрыть все дескрипторы открытого файла, не имея заранее явного списка их?
Ответы:
Чтобы ответить буквально, закройте все дескрипторы открытого файла для 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.
/proc/PID/fd
это не очень удобно. Но говорить, что /proc
доступно только под Linux, не является правильным утверждением.
<&-
форму, она отличается от других / нужна?
В последних версиях Bash (4.1 и более поздних, 2009 и более поздних) вы можете указать дескриптор файла, который нужно закрыть, используя переменную оболочки:
for fd in $(ls /proc/$$/fd/); do
[ $fd -gt 2 ] && exec {fd}<&-
done
Эта функция уже была в оболочке Korn (с 1993 года?), Но, видимо, потребовалось некоторое время, чтобы проникнуть в Bash.
Очистить все файловые дескрипторы, кроме ввода / вывода текущей оболочки, но также исключить те, которые представлены в качестве аргументов
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
}
Еще один способ вообще не использовать 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
Нет. Ядро может закрывать только один FD за раз, и bash не имеет «групповых команд» для FD.
for fd in $(ls -1 /proc/27343/fd); do echo exec $fd">&"-; done
Удалить echo
и "
после тестирования.
Если это не для самой оболочки, а для запуска команды, вы можете использовать nohup
.
>&-
не может быть параметром; перенаправление анализируется перед расширением параметра.
exec {fd}>&-
работает.