Не нужно и ls
не grep
нужно ничего открывать на их fd 3 (они не используют этот fd), поэтому лучше практиковаться, чтобы закрыть его (освободить ресурсы, которые вам не нужны). Мы используем этот fd 3 только для того, чтобы иметь возможность восстановить стандартный ls
вывод (до выполнения ls
).
Помните, что в конвейере все команды выполняются одновременно в своем собственном процессе. Перенаправления применяются для каждого отдельно, поэтому закрытие fd 3 для одного не может закрыть его для другого.
В этом случае на практике не будет большой разницы закрывать или не закрывать, кроме того, что вы могли бы достичь ограничения числа дескрипторов файлов раньше, если вы этого не сделаете.
В других случаях (например, команды сами запускают другие процессы), это может удерживать ресурсы и вызывать проблемы. Подумайте, например, что если stdout является, например, каналом, то фоновый процесс может в конечном итоге унаследовать этот fd, не позволяя любому читателю из этого канала видеть EOF до тех пор, пока этот процесс не вернется.
Лучший способ написать это было бы:
{ ls -l 2>&1 >&3 3>&- | grep bad 3>&-; } 3>&1
Таким образом, fd 3 временно перенаправляется только на время действия этой группы команд (и восстанавливается впоследствии или закрывается).
Увидеть разницу:
$ { ls -l /proc/self/fd 2>&1 >&3 3>&- | grep bad 3>&-; } 3>&1
total 0
lrwx------ 1 stephane stephane 64 Apr 2 09:29 0 -> /dev/pts/4
lrwx------ 1 stephane stephane 64 Apr 2 09:29 1 -> /dev/pts/4
l-wx------ 1 stephane stephane 64 Apr 2 09:29 2 -> pipe:[575886]
lr-x------ 1 stephane stephane 64 Apr 2 09:29 3 -> /proc/20918/fd/
$ { ls -l /proc/self/fd 2>&1 >&3 | grep bad 3>&-; } 3>&1
total 0
lrwx------ 1 stephane stephane 64 Apr 2 09:29 0 -> /dev/pts/4
lrwx------ 1 stephane stephane 64 Apr 2 09:29 1 -> /dev/pts/4
l-wx------ 1 stephane stephane 64 Apr 2 09:29 2 -> pipe:[575900]
lrwx------ 1 stephane stephane 64 Apr 2 09:29 3 -> /dev/pts/4
lr-x------ 1 stephane stephane 64 Apr 2 09:29 4 -> /proc/20926/fd/
Во втором вызове ls
fd 3 также был открыт для терминала (который был открыт на stdout во время запуска конвейера) без веской причины.
Обратите внимание, что в ksh93, с exec
, вам не нужно закрывать эти fds, поскольку fds, кроме 0, 1, 2, автоматически закрываются при выполнении команды.
$ ksh93 -c 'exec 3>&1; ls -l /dev/fd/'
total 0
lrwx------ 1 stephane stephane 64 Apr 2 09:34 0 -> /dev/pts/16
lrwx------ 1 stephane stephane 64 Apr 2 09:34 1 -> /dev/pts/16
lrwx------ 1 stephane stephane 64 Apr 2 09:34 2 -> /dev/pts/16
lr-x------ 1 stephane stephane 64 Apr 2 09:34 3 -> /proc/21105/fd
$ ksh93 -c 'exec 3>&1; ls -l /dev/fd/ 3>&3'
total 0
lrwx------ 1 stephane stephane 64 Apr 2 09:34 0 -> /dev/pts/16
lrwx------ 1 stephane stephane 64 Apr 2 09:34 1 -> /dev/pts/16
lrwx------ 1 stephane stephane 64 Apr 2 09:34 2 -> /dev/pts/16
lrwx------ 1 stephane stephane 64 Apr 2 09:34 3 -> /dev/pts/16
lr-x------ 1 stephane stephane 64 Apr 2 09:34 4 -> /proc/21108/fd
Я не знаю, почему он говорит (но не «ls») выше, звучит как ошибка (возможно, моя ;-).
#Thanks, S.C
там значит?3>&-
(дляls
части). Описано ли где-нибудь, в каком порядке создаются дескрипторы и / или каналы?fd3
Дважды закройте, потому что вы раскручиваете две подоболочки в скрипте, каждая подоболочка наследуется и копируется дескриптор файла родителя. Закрытиеfd3
в каждой подоболочке не влияет на других (и на родителя тоже).Таким образом, строка комментария очень непонятна и вызывает заблуждение.
Если вы хотите перенаправить только
stder
на канал, вы можете использоватьprocess substitution
:или поменяйте местами
stderr
иstdout
:источник