Czy istnieje sposób na zamknięcie wszystkich otwartych deskryptorów plików bez uprzedniej ich jawnej listy?
Czy istnieje sposób na zamknięcie wszystkich otwartych deskryptorów plików bez uprzedniej ich jawnej listy?
Odpowiedzi:
Aby odpowiedzieć dosłownie, zamknąć wszystkie otwarte deskryptory plików dla bash
:
for fd in $(ls /proc/$$/fd); do
eval "exec $fd>&-"
done
Jednak to naprawdę nie jest dobry pomysł, ponieważ spowoduje zamknięcie podstawowych deskryptorów plików wymaganych przez powłokę dla danych wejściowych i wyjściowych. Jeśli to zrobisz, żaden z uruchomionych programów nie będzie wyświetlał danych wyjściowych na terminalu (chyba że zapisują tty
bezpośrednio w urządzeniu). Jeśli fakt w moich testach zamknięcie stdin
( exec 0>&-
) powoduje jedynie zamknięcie interaktywnej powłoki.
To, czego właściwie możesz chcieć, to raczej zamknąć wszystkie deskryptory plików, które nie są częścią podstawowej operacji powłoki. Są to 0 dla stdin
, 1 dla stdout
i 2 dla stderr
. Ponadto niektóre powłoki wydają się mieć domyślnie otwarte inne deskryptory plików. W bash
, na przykład, mieć 255 (również dla zacisku wejścia / wyjścia) oraz dash
, że nie więcej niż 10, co wskazuje /dev/tty
, a nie konkretnych tty
/ pts
urządzenia terminala jest używany. Aby zamknąć wszystko oprócz 0, 1, 2 i 255 w bash
:
for fd in $(ls /proc/$$/fd); do
case "$fd" in
0|1|2|255)
;;
*)
eval "exec $fd>&-"
;;
esac
done
Należy również zauważyć, że eval
jest wymagana, gdy przekierowanie deskryptor pliku zawartego w zmiennej, jeśli nie bash
wzrośnie zmienną, ale uważają, że część komendy (w tym przypadku byłoby spróbować exec
polecenia 0
lub 1
lub inny plik deskryptora staramy się blisko).
UWAGA: Również użycie glob zamiast ls
(np. /proc/$$/fd/*
) Wydaje się otwierać dodatkowy deskryptor pliku dla glob, więc ls
wydaje się tutaj najlepszym rozwiązaniem.
Aby uzyskać więcej informacji na temat przenośności /proc/$$/fd
, zobacz Przenośność linków deskryptorów plików . Jeśli /proc/$$/fd
jest niedostępne, oznacza to spadek w zamian za $(ls /proc/$$/fd)
użycie lsof
(jeśli jest dostępne) $(lsof -p $$ -Ff | grep f[0-9] | cut -c 2-)
.
/proc
jest dostępny tylko w systemie Linux.
/proc/PID/fd
to nie jest bardzo przenośne. Ale powiedzenie, że /proc
jest dostępne tylko pod Linuksem, nie jest poprawnym stwierdzeniem.
<&-
formularza, czy jest on inny / potrzebny?
W ostatnich wersjach bash (4.1 i nowsze, rok 2009 i później), które można określić deskryptor pliku do zamknięcia za pomocą zmiennej powłoki:
for fd in $(ls /proc/$$/fd/); do
[ $fd -gt 2 ] && exec {fd}<&-
done
Ta funkcja była już w skorupie Korna (od 1993 roku?), Ale najwyraźniej zajęła trochę czasu, aby dostać się do Bash.
Wyczyść wszystkie deskryptory plików oprócz I / O / e bieżącej powłoki, ale również wyklucza te podane jako argumenty
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
}
Innym sposobem bez „ewaluacji” jest użycie formularza:
$ 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
Nie. Jądro może zamykać tylko jedną FD na raz, a bash nie ma „komend grupowych” dla FD.
for fd in $(ls -1 /proc/27343/fd); do echo exec $fd">&"-; done
Usuń echo
i "
po testach.
Jeśli nie dotyczy to samej powłoki, ale polecenia, które należy uruchomić, możesz użyć nohup
.
>&-
nie może być parametrem; przekierowanie jest analizowane przed rozszerzeniem parametru.
exec {fd}>&-
działa.