Если вы можете исходный код
скрипта, вы можете его прочитать. cat / path / to / script
отобразит содержимое script
.
Поддержка {var}>...
была добавлена в ksh93
, bash
и zsh
одновременно по предложению разработчика zsh
. Оператор {var}>...
работает в zsh
, но не для составных команд.
Также обратите внимание, что в:
cmd 3>&1
fd 3 открыт только для cmd
, в
cmd {var}>&1
Динамически выделенный fd (, сохраненный в $var
), остается открытым после того, как cmd
возвращается как в zsh
, так и в bash
. Этот оператор в основном предназначен для использования с exec
(. См. также sysopen
в zsh
для более простого интерфейса к системному вызову open()
).
Таким образом, в приведенном выше коде отсутствует exec {tmp}>&-
для последующего освобождения этого fd в bash
.
Так что здесь можно сделать:
if exec {tmp}>&1; then
errors=$(exec 2>&1 >&"$tmp" {tmp}>&- && ls -ld /x /bin | tr o Z)
exec {tmp}>&-
fi
Что будет работать в bash
, zsh
и ksh93
и не приведет к утечке fd. (кавычки вокруг $tmp
необходимы только в bash
и когда параметр posix
не включен ). Обратите внимание, что в ksh93
или когда zsh
или bash
находятся в режиме POSIX,сбой exec
приводит к выходу оболочки(dup()
сбой здесь может быть вызван закрытием stdout или некоторым ограничением на количество открытых файлов или другими патологическими случаями, для которых вы все равно можете выйти ).
Но здесь вам не нужен динамически выделяемый fd, просто используйте, например, fd 3, который не используется в этом коде:
{ errors=$(exec 2>&1 >&3 3>&-; ls -ld /x /bin | tr o Z); } 3>&1
Что будет работать в любой -Bourne-подобной оболочке.
Как и в описанном выше подходе с динамическим fd, даже если это не так очевидно, в случае сбояdup2()
(в3>&1
)назначение не будет выполнено, поэтому вы можете убедиться, что errors
инициализирован до (. ] с unset -v errors
, например ).
Обратите внимание, что не имеет значения, открыт ли fd 3 иным образом или используется в остальной части скрипта (, исходный fd, если он открыт, останется нетронутым и будет восстановлен в конце ). ожидает ли код, встроенный в $(...)
, открытость fd 3.
Ожидается, что только fds 0, 1 и 2 будут открыты приложениями, другие fds — нет. ls
и tr
ничего не ожидают от fd 3. Случаи, когда вам может понадобиться использовать другой fd, — это когда ваш код явно использует этот fd и ожидает, что он был открыт заранее например, если бы вместо ls
у вас было cat /dev/fd/3
, где ожидается, что fd 3 был открыт для какого-то ресурса где-то ранее в вашем скрипте.
Чтобы ответить на вопрос о том, как назначить первый свободный fd в оболочках POSIX, я не думаю, что есть способ с помощью оболочки POSIX и API утилит. Это также может не иметь смысла. Оболочка может делать то, что она хочет внутри, с любым fd при условии, что это не мешает ее собственному API. Например, вы можете обнаружить, что fd 11 сейчас свободен, но позже может использоваться оболочкой для чего-то внутреннего, и ваши записи в него могут повлиять на его поведение. Также обратите внимание, что в POSIX sh вы можете манипулировать только fds от 0 до 9.