Щоб зберегти дескриптор файлу, ви дублюєте його на іншому fd. Збереження шляху до відповідного файлу недостатньо, вам потрібно буде зберегти режим відкриття, прапорці відкриття, поточне положення у файлі тощо. І звичайно, для анонімних труб або розеток це не спрацює, оскільки до них немає шляху. Те, що ви хочете зберегти, - це відкритий опис файлу , на який посилається fd, і копіювання fd насправді повертає новий fd до того ж опису відкритого файлу .
Для дублювання дескриптора файлу на інший, з оболонкою Борна, синтаксис:
exec 3>&1
Вище fd 1 дублюється на fd 3.
Що б fd 3 вже не було відкрито, було б закрито, але зауважте, що FDS 3 до 9 (зазвичай більше, до 99 с yash
) зарезервовані для цієї мети (і не мають особливого значення всупереч 0, 1 або 2), shell знає, що не використовує їх для власного внутрішнього бізнесу. Єдина причина, що fd 3 була б відкрита заздалегідь, це те, що ви зробили це в сценарії 1 , або його витік абонент.
Потім ви можете змінити stdout на щось інше:
exec > /dev/null
І пізніше, щоб відновити stdout:
exec >&3 3>&-
( 3>&-
будучи закрити дескриптор файлу, який нам більше не потрібен).
Тепер проблема полягає в тому, що за винятком ksh, кожна команда, яку ви запускаєте після цього exec 3>&1
, успадковуватиме цей fd 3. Це fd leak. Зазвичай це не велика справа, але це може спричинити проблеми.
ksh
встановлює прапор close-on-exec на цих FDS (для FDS понад 2), але інші оболонки та інші оболонки не мають жодного способу встановити цей прапор вручну.
Робота навколо іншої оболонки полягає в тому, щоб закрити fd 3 для кожної команди, наприклад:
exec 3>&-
exec > file.log
ls 3>&-
uname 3>&-
exec >&3 3>&-
Громіздкий. Тут найкращим способом було б взагалі не використання exec
командних груп перенаправлення:
{
ls
uname
} > file.log
Там саме оболонка дбає про збереження stdout та відновлення його після цього (і це робиться всередині, дублюючи його на fd (вище 9, вище 99 для yash
) із встановленим прапором close-on-exec ).
Примітка 1
Тепер управління цими FDS 3 на 9 може бути громіздким і проблематичним, якщо ви використовуєте їх широко або у функціях, особливо якщо ваш сценарій використовує якийсь сторонній код, який, в свою чергу, може використовувати ці файли.
Деякі оболонки ( zsh
, bash
, ksh93
, все додали функцію ( запропонований Oliver Кіддл зzsh
) приблизно в той же час в 2005 році після того, як його було обговорено серед їх розробників) мають альтернативний синтаксис , щоб призначити перший вільний FD вище 10 замість , який допомагає в цьому випадку:
myfunction() {
local fd
exec {fd}>&1
# stdout was duplicated onto a new fd above 10, whose actual value
# is stored in the fd variable
...
# it should even be safe to re-enter the function here
...
exec >&"$fd" {fd}>&-
}