Перенаправление ввода-вывода в bash

Когда я начинал изучать написание сценариев bash, была такая штука, которую я никак не мог понять — перенаправление ввода-вывода. Снова и снова я перечитывал документацию, дословно переписывал оттуда положенные циферки и амперсанды, но никак не мог понять расстановки этих самых магических символов.

Я предполагаю, что вы знакомы с понятиями «файловый дескриптор», «поток ввода (вывода)», «конвейер» и т.д., но просто никак не можете запомнить, как всем этим пользоваться. На самом деле все просто. Смотрите.

Команда перенаправления вывода позволяет все, что записывается в один файловый дескриптор (откуда), записать вместо этого в другой файловый дескриптор (куда):

откуда > куда

Что может быть на месте откуда:

  • ничего: перенаправление из дескриптора 1 (stdout);
  • i: перенаправление из дескриптора i;
  • &: перенаправляются сразу stdout и stderr.

Что может быть на месте куда:

  • &j: перенаправление в дескриптор j;
  • имя файла: файл открывается в режиме записи, и перенаправление осуществляется в него.

Если используется оператор перенаправления >> (дописать в конец) вместо > (очистить и писать сначала), то куда может быть только именем файла.

Указываемый дескриптор не обязательно должен быть открыт. Номера с 3 по 9 можно использовать как «перевалочные пункты»; открытые файлы получают дескрипторы, начиная с 10.

Перенаправление ввода работает очень похоже:

куда < откуда

Теперь при чтении из куда на самом деле чтение будет происходить из откуда. Тут по сравнению с перенаправлением вывода все наоборот. Куда может быть пустым (stdin) или номером дескриптора. Заметьте, что символ & здесь уже не годится — нельзя читать из двух потоков сразу. Откуда может быть или вида &i, или именем файла, который при этом открывается для чтения.

Указанное в команде перенаправление работает только для одной строки сценария; чтобы перенаправление было постоянным, нужно выполнить его с помощью exec. В одной строке можно указывать несколько перенаправлений, причем они комбинируются. Например:

ps -aF > myfile 2>&1

Здесь сначала stdout перенаправляется в файл, а затем stderr перенаправляется в stdout. В результате и stdout, и stderr перенаправляются в файл. Замечу, что перенаправление выполняется по порядку. То есть, такая команда будет работать по-другому:

ps -aF 2>&1 > myfile

Здесь stderr будет выведет на консоль. Правило простое: перенаправление происходит в текущую конечную точку перенаправления дескриптора (если не поняли, прочитайте предложение еще раз).

Еще один тонкий момент: как быть с конвейерами? Распространяется ли действие перенаправления на весь конвейер? Правила просты:

  • перенаправление действует только на ту команду в конвейере, где оно задано;
  • команда выдает в конвейер данные, выведенные в дескриптор 1 (с учетом перенаправлений);
  • команда берет из конвейера данные, полученные из дескриптора 0 (с учетом перенаправлений).

Например, вот так можно перенаправить поток ошибок в конвейер:

ps -aF 3>&1 1>&2 2>&3 | grep something

Здесь stderr и stdout фактически меняются местами.

Конечно, можно много чего еще сказать по поводу перенаправления: про одновременное перенаправление и ввода, и вывода, про перенаправление блока команд, про перенаправление с помощью exec, про закрытие дескрипторов и т.д. Но тогда пост получится слишком объемным, и им неудобно будет пользоваться как справкой. Если у вас есть какие-то вопросы, готов ответить в комментариях. За найденные ошибки также буду признателен.

УжасноПлохоНормальноХорошоОтлично (4 голосов, средний: 5,00 из 5)
Loading ... Loading ...

3 комментария

Оставьте свой отзыв

Или введите OpenId:

XHTML: Можно использовать следующие теги: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre lang="" line="" escaped="" highlight="">