Глава 16. Перенаправление ввода/вывода | Популярный Linux

Опубликовано Bash в Ср, 23/12/2009 — 20:59


В системе по-умолчанию всегда открыты три «файла»stdin (клавиатура), stdout (экран) и stderr (вывод сообщений об ошибках на экран). Эти, и любые другие открытые файлы, могут быть перенапрвлены. В данном случае, термин «перенаправление» означает получить вывод из файла, команды, программы, сценария или даже отдельного блока в сценарии (см. Пример 3-1 и Пример 3-2) и передать его на вход в другой файл, команду, программу или сценарий.

С каждым открытым файлом связан дескриптор файла. [45] Дескрипторы файлов stdin, stdout и stderr — 0, 1 и 2, соответственно. При открытии дополнительных файлов, дескрипторы с 3 по 9 остаются незанятыми. Иногда дополнительные дескрипторы могут сослужить неплохую службу, временно сохраняя в себе ссылку на stdin, stdout или stderr. [46] Это упрощает возврат дескрипторов в нормальное состояние после сложных манипуляций с перенаправлением и перестановками (см. Пример 16-1).

  1.    COMMAND_OUTPUT >
  2.       # Перенаправление stdout (вывода) в файл.
  3.       # Если файл отсутствовал, то он создется, иначе — перезаписывается.
  4.       ls -lR > dir-tree.list
  5.       # Создает файл, содержащий список дерева каталогов.
  6.    : > filename
  7.       # Операция > усекает файл «filename» до нулевой длины.
  8.       # Если до выполнения операции файла не существовало,
  9.       # то создается новый файл с нулевой длиной (тот же эффект дает команда ‘touch’).
  10.       # Символ : выступает здесь в роли местозаполнителя, не выводя ничего.
  11.    > filename
  12.       # Операция > усекает файл «filename» до нулевой длины.
  13.       # Если до выполнения операции файла не существовало,
  14.       # то создается новый файл с нулевой длиной (тот же эффект дает команда ‘touch’).
  15.       # (тот же результат, что и выше — «: >», но этот вариант неработоспособен
  16.       # в некоторых командных оболочках.)
  17.    COMMAND_OUTPUT >>
  18.       # Перенаправление stdout (вывода) в файл.
  19.       # Создает новый файл, если он отсутствовал, иначе — дописывает в конец файла.
  20.       # Однострочные команды перенаправления
  21.       # (затрагивают только ту строку, в которой они встречаются):
  22.       # ———————————————————————
  23.    1>filename
  24.       # Перенаправление вывода (stdout) в файл «filename».
  25.    1>>filename
  26.       # Перенаправление вывода (stdout) в файл «filename», файл открывается в режиме добавления.
  27.    2>filename
  28.       # Перенаправление stderr в файл «filename».
  29.    2>>filename
  30.       # Перенаправление stderr в файл «filename», файл открывается в режиме добавления.
  31.    &>filename
  32.       # Перенаправление stdout и stderr в файл «filename».
  33.       #==============================================================================
  34.       # Перенаправление stdout, только для одной строки.
  35.       LOGFILE=script.log
  36.       echo «Эта строка будет записана в файл $LOGFILE 1>$LOGFILE
  37.       echo «Эта строка будет добавлена в конец файла $LOGFILE 1>>$LOGFILE
  38.       echo «Эта строка тоже будет добавлена в конец файла $LOGFILE 1>>$LOGFILE
  39.       echo «Эта строка будет выведена на экран и не попадет в файл $LOGFILE
  40.       # После каждой строки, сделанное перенаправление автоматически «сбрасывается».
  41.       # Перенаправление stderr, только для одной строки.
  42.       ERRORFILE=script.errors
  43.       bad_command1 2>$ERRORFILE       #  Сообщение об ошибке запишется в $ERRORFILE.
  44.       bad_command2 2>>$ERRORFILE      #  Сообщение об ошибке добавится в конец $ERRORFILE.
  45.       bad_command3                    #  Сообщение об ошибке будет выведено на stderr,
  46.                                       #+ и не попадет в $ERRORFILE.
  47.       # После каждой строки, сделанное перенаправление также автоматически «сбрасывается».
  48.       #==============================================================================
  49.    2>&1
  50.       # Перенаправляется stderr на stdout.
  51.       # Сообщения об ошибках передаются туда же, куда и стандартный вывод.
  52.    i>&j
  53.       # Перенаправляется файл с дескриптором i в j.
  54.       # Вывод в файл с дескриптором i передается в файл с дескриптором j.
  55.    >&j
  56.       # Перенаправляется  файл с дескриптором 1 (stdout) в файл с дескриптором j.
  57.       # Вывод на stdout передается в файл с дескриптором j.
  58.    0< FILENAME
  59.     < FILENAME
  60.       # Ввод из файла.
  61.       # Парная команде «>», часто встречается в комбинации с ней.
  62.       #
  63.       # grep search-word <filename
  64.    [j]<>filename
  65.       # Файл «filename» открывается на чтение и запись, и связывается с дескриптором «j».
  66.       # Если «filename» отсутствует, то он создается.
  67.       # Если дескриптор «j» не указан, то, по-умолчанию, бередся дескриптор 0, stdin.
  68.       #
  69.       # Как одно из применений этого — запись в конкретную позицию в файле.
  70.       echo 1234567890 > File    # Записать строку в файл «File».
  71.       exec 3<> File       # Открыть «File» и связать с дескриптором 3.
  72.       read -n 4 <&3             # Прочитать 4 символа.
  73.       echo -n . >&3             # Записать символ точки.
  74.       exec 3>&—                 # Закрыть дескриптор 3.
  75.       cat File                  # ==> 1234.67890
  76.       # Произвольный доступ, да и только!
  77.    |
  78.       # Конвейер (канал).
  79.       # Универсальное средство для объединения команд в одну цепочку.
  80.       # Похоже на «>», но на самом деле — более обширная.
  81.       # Используется для объединения команд, сценариев, файлов и программ в одну цепочку (конвейер).
  82.       cat *.txt | sort | uniq > result-file
  83.       # Содержимое всех файлов .txt сортируется, удаляются повторяющиеся строки,
  84.       # результат сохраняется в файле «result-file».

Операции перенаправления и/или конвейеры могут комбинироваться в одной командной строке.

  1. command < input-file > output-file
  2. command1 | command2 | command3 > output-file

См. Пример 12-26 и Пример
A-17
.

Допускается перенаправление нескольких потоков в один файл.

  1. ls -yz >> command.log 2>&1
  2. # Сообщение о неверной опции «yz» в команде «ls» будет записано в файл «command.log».
  3. # Поскольку stderr перенаправлен в файл.
  4. #  Обратите внимание: следующая строка даст иной результат.
  5. ls -yz 2>&1 >> command.log
  6. #  Сообщение об ошибке не попадет в файл.
  7. #  Если производится перенаправление обоих устройств, stdout и stderr,
  8. #+ то порядок действий изменяется.

Закрытие дескрипторов файлов

n<&-

Закрыть дескриптор входного файла n.

0<&-, <&-

Закрыть stdin.

n>&-

Закрыть дескриптор выходного файла n.

1>&-, >&-

Закрыть stdout.

Дочерние процессы наследуют дескрипторы открытых файлов. По этой причине и работают конвейеры. Чтобы предотвратить наследование дескрипторов — закройте их перед запуском дочернего процесса.

  1. # В конвейер передается только stderr.
  2. exec 3>&1                              # Сохранить текущее «состояние» stdout.
  3. ls -l 2>&1 >&3 3>&| grep bad 3>&—    # Закрыть дескр. 3 для ‘grep’ (но не для ‘ls’).
  4. #              ^^^^   ^^^^
  5. exec 3>&—                              # Теперь закрыть его для оставшейся части сценария.
  6. # Спасибо S.C.

Дополнительные сведения о перенаправлении ввода/вывода вы найдете в Приложение E.


[45]    дескриптор файла — это просто число, по которому система идентифицирует открытые файлы. Рассматривайте его как упрощенную версию указателя на файл.

[46]    При использрвании дескриптора с номером 5 могут возникать проблемы. Когда Bash порождает дочерний процесс, например командой exec, то дочерний процесс наследует дескриптор 5 как «открытый» (см. архив почты Чета Рамея (Chet Ramey), SUBJECT: RE: File descriptor 5 is held open) Поэтому, лучше не использовать этот дескриптор.

Запись опубликована в рубрике Без рубрики. Добавьте в закладки постоянную ссылку.