Закрытие файлового дескриптора,> & - vs <& -

49

В учебнике bash, который я читаю, говорится, что если вы откроете дескриптор файла для чтения, т.е.

exec 3< echolist

Тогда вы должны закрыть это так,

exec 3<&-

Однако, если вы открываете дескриптор файла для записи, он должен быть закрыт следующим образом:

exec 3>&-

Тем не менее, когда я смотрю в Интернете, я вижу людей, открывающих файлы, а затем закрывающих их следующим образом:

exec 3>&- 

ПРИМЕЧАНИЕ: когда, согласно учебнику, они должны использовать exec 3<&1.

Итак, мой вопрос, все ли файловые дескрипторы могут быть закрыты через exec n>&-где n - номер файлового дескриптора? Независимо от того, был ли он открыт для чтения, письма или и того, и другого?

Джейсон
источник
21
Единственное различие между >&-и <&-является Ф.Д. по умолчанию , если не указано ( >&-в 1>&-то время как <&-есть 0<&-). То же самое для x>&yчего то же самое, x<&yза исключением случаев, когда xне предусмотрено.
Стефан Шазелас

Ответы:

48

Вы можете закрыть дескриптор файла, используя оба <&-и >&-, bashпроанализирует два синтаксиса как один и тот же.

Из файла y.tab.c в bashисходном коде:

5385   /* Hack <&- (close stdin) case.  Also <&N- (dup and close). */                
5386   if MBTEST(character == '-' && (last_read_token == LESS_AND || last_read_token == GREATER_AND))
5387     return (character);
cuonglm
источник
2
Это также может быть использовано в <>файловых дескрипторах.
CMCDragonkai
1
Нет, это невозможно, но, как в 3>&-или 3<&-кажется, чтобы закрыть дескриптор.
CMCDragonkai
1
Это закрытие <>может быть сделано теми же способами.
CMCDragonkai
1
Я не могу понять, что вы имеете в виду. Пожалуйста, приведите пример
./
1
Я не думаю, что это то, что я имел в виду. Просто дескриптор файла для чтения и записи может быть закрыт с помощью 3> & - и 3 <& -.
CMCDragonkai
15

Насколько я могу видеть, exec 3>&-и exec 3<&-то же самое и может быть использован на любом файле дескриптора, независимо от того, как он был открыт. В соответствии с разделами 2.7.6 и 2.7.5 определения POSIX языка командной оболочки :

2.7.5 Дублирование дескриптора входного файла

Оператор перенаправления:

[П] <& слово

[... СНИП ...]

Если слово оценивается как '-', дескриптор файла n или стандартный ввод, если n не указано, должны быть закрыты. Попытки закрыть дескриптор файла, который не открыт, не являются ошибкой. Если слово оценивает что-то еще, поведение не определено.

2.7.6 Дублирование дескриптора выходного файла

Оператор перенаправления:

[П]> & слово

[... СНИП ...]

Если слово оценивается как '-', дескриптор файла n или стандартный вывод, если n не указано, закрывается. Попытки закрыть дескриптор файла, который не открыт, не являются ошибкой. Если слово оценивает что-то еще, поведение не определено.

Обратите внимание, что ни один из них не указывает, как изначально был открыт файловый дескриптор n. Это соответствует тому факту, что close (2) не заботится о том, как вы открыли файл.

Быстрое следующее:

exec 3< /etc/passwd
exec 4> foo
exec 3<&-
exec 4<&-

по сравнению с этим:

exec 3< /etc/passwd
exec 4> foo
exec 3<&-
exec 4>&-

показывает, что в обоих случаях Bash делает одно и то же.

Два слегка интересных факта

Стивен Д
источник
1
Страница man bash упоминает о закрытии, цитируя вашу ссылку: Если слово имеет значение '-', дескриптор файла n закрывается.
Стадог
@studog Спасибо за проверку источника! Я думаю, что здесь произошло, я просматривал локальную справочную страницу для Bash 3, а затем связался с онлайн-документацией, которая была для Bash 4. В старой документации Bash 3 фраза о закрытии была опущена в описании [N]>&WORD: git .savannah.gnu.org / cgit / bash.git / tree / doc /…
Стивен Д.
7

Пример для понимания cuonglm закрытия '<>' FD.

Это цитируется в Расширенном руководстве по написанию сценариев на http://tldp.org/LDP/abs/html/io-redirection.html.

[j]<>filename
  #  Open file "filename" for reading and writing,
  #+ and assign file descriptor "j" to it.
  #  If "filename" does not exist, create it.
  #  If file descriptor "j" is not specified, default to fd 0, stdin.
  #
  #  An application of this is writing at a specified place in a file. 
  echo 1234567890 > File    # Write string to "File".
  exec 3<> File             # Open "File" and assign fd 3 to it.
  read -n 4 <&3             # Read only 4 characters.
  echo -n . >&3             # Write a decimal point there.
  exec 3>&-                 # Close fd 3.
  cat File                  # ==> 1234.67890
  #  Random access, by golly.
DMW
источник