Щоб зберегти дескриптор файлу, ви дублюєте його на іншому 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}>&-
}