Перенаправление потоков в Linux. Вывод команды в файл

Системное администрирование Linux-систем, да и вообще администрирование любой UNIX-подобной системы. Неразрывно связано с работой в командных оболочках. Для опытных системных администраторов такой способ взаимодействия с системой является гораздо более удобным и быстрым, нежели использование графических оболочек и интерфейсов. Конечно, это многим сразу покажется преувеличением, но это неоспоримый факт. Постоянно подтверждаемый на практике. А возможна такая ситуация благодаря некоторым хитростям и инструментам, используемых при работе с командной консолью. И одним из таких инструментов является использование информационных каналов и перенаправления потоков данных для процессов.

Немного теории

Следует начать с того, что для каждого процесса система предоставляет в «пользование» как минимум три информационных канала:

  • STDIN – стандартный ввод;
  • STDOUT – стандартный вывод;
  • STDERR – стандартная ошибка.

Строгой принадлежности этих каналов для каждого процесса нет. Сами процессы изначально появившись в системе «не знают» о том, кому и как принадлежат каналы. Они (каналы) являются общесистемным ресурсом. Хотя и устанавливаются ядром от имени процесса. Каналы могут связывать файлы, каналы, связывающие другие процессы, подключения к сети и т. д.

В UNIX-подобных системах, согласно модели ввода-вывода. Каждому из информационных каналов присваивается целочисленное значение в качестве номера. Однако для безопасного доступа. к вышеприведённым каналам. За ними зарезервированы постоянные номера — 0, 1 и 2 для STDIN, STDOUT и STDERR соответственно. Во время выполнения процессов считывание входных данных происходит по STDIN. Через клавиатуру, с вывода другого процесса, файла и т. д.. А выходные данные (через STDOUT), а также данные об ошибках (через STDERR). Выводятся на экран, в файл, на вход (уже через STDIN другого процесса) в другую программу.

Для изменения направления информационных каналов и связи их с файлами существуют специальные инструкции в виде символов <, > и >>. Так, например инструкцией < можно заставить направить процессу по STDIN содержимое файла. А с помощью инструкции > процесс по STDOUT передаёт выходные данные в файл, при этом заменяется всё содержимое существующего файла целиком. При отсутствии он будет создан. Инструкция >> выполняет то же самое, что и >, но не перезаписывает файл, а дописывает вывод в его конец. Для объединения потоков (т. е. для направления их в один и тот же приёмник) STDOUT и STDERR нужно использовать конструкцию >&. Для направления одного из потоков, например STDERR в отдельное место существует инструкция 2>.

Для связывания между собой двух каналов. Например когда нужно вывод одной команды направить на вход другой. Следует использовать для этого инструкцию (символ) «|». Который означает логическую операцию «или». Однако в контексте связывания потоков данная интерпретация не имеет значения, что нередко сбивает с толку новичков. Благодаря таким возможностям можно составлять целые командные конвейеры. Что делает работу в командных оболочках очень эффективной.

Вывод в файл

Направление вывода команды и запись этого вывода в файл /tmp/somemessage:

$ echo “This is a test message” > /tmp/somemessage

В данном случае в качестве команды с выхода которой (по STDOUT) перенаправляются данные в виде текста «This is a test massage» является утилита echo. В результате создасться файл /tmp/somemessage, в котором будет запись «This is a test message». Если файл не был создан то он создасться, если создан, то все данные в нем перезапишутся. Если нужно дописать вывод в конец файла, нужно использовать оператор «>>»

$ echo “This is a test message” >> /tmp/somemessage
$ cat /tmp/somemessage
This is a test message
This is a test message

Как видим из примера вторая команда дописала строчку в конец файла.

Получение данных из файла

Следующий пример демонстрирует перенаправление входа:

$ mail -s "Mail test" john < /tmp/somemessage

В правой части команды (после символа <) находится файл-источник /tmp/somemesage, содержимое которого перенаправляется в утилиту mail (через STDIN), которая в свою очередь, имеет в качестве собственных параметров заголовок письма и адресата (john).

Другие примеры

Следующий пример показывает, почему иногда очень полезно разделять потоки из каналов STDIN и STDERR:

$ find / -name core 2> /dev/null

Дело в том, что команда find / -name core будет «сыпать» сообщениями об ошибках, направляя их по-умолчанию в то же место, что и результаты поиска. Т. е. в терминал командной консоли, что существенно затруднит восприятие информации пользователем. Т. к. искомые результаты затеряются среди многочисленных сообщений об ошибках, связанных с режимом доступа. Конструкция 2>/dev/null заставляет утилиту find отправлять сообщения об ошибках (следующие по каналу STDERR с зарезервированным номером 2) на фиктивное устройство /dev/null, оставляя в выводе только результаты поиска.

Если нужно сохранить результаты поиска из предыдущего примера в файл, нужно для этого дать команду:

$ find / -name core > /tmp/corefiles 2> /dev/null

Здесь конструкция > /tmp/corefiles перенаправляет вывод утилиты find (по каналу STDOUT) в файл /tmp/corefiles. Сообщения об ошибках отсеиваются на /dev/null, не попадая в вывод терминала командной консоли.

Для связывания между собой разных каналов для разных команд:

$ fsck --help | drep M

-M   не проверять примонтированные файловые системы

Эта команда выведет строку (или строки), содержащие символ «M» из страницы быстрой справки к утилите fsck. Это очень удобно, когда нужно посмотреть только интересующую информацию. В данном случае утилита grep получает вывод (по инструкции |) от команды fsck —help. И далее по шаблону «M» отбрасывает всё лишнее.

Если нужно, чтобы следующая в конвейере команда выполнялась только после полного и успешного завершения предыдущей команды, то для этого следует использовать инструкцию &&, например:

$ lpr /tmp/t2 && rm /tmp/page1

Эта команда удалит файл /tmp/page1 только тогда, когда содержимое из него будет отправлено из очереди на печать. Для достижения обратного эффекта, т. е. когда нужно выполнение следующей команды в конвейере только после того, как предыдущая не выполнится (завершится с ошибкой с ненулевым кодом), то следует использовать конструкцию ||.

Когда строка кода, включающая слишком длинный конвейер команд тяжело воспринимается, можно разбивать её на логические компоненты по строкам с помощью символа обратной черты «\»:

$ ср --preserve --recursive /etc/* /spare/backup \
|| echo "Make backup error"

Отдельные команды, которые должны выполняться друг за другом можно объединять в одну строку, разделяя их символом двоеточия «;»:

Если вы нашли ошибку, пожалуйста, выделите фрагмент текста и нажмите Ctrl+Enter.

Понравилась статья? Поделиться с друзьями:
Добавить комментарий

;-) :| :x :twisted: :smile: :shock: :sad: :roll: :razz: :oops: :o :mrgreen: :lol: :idea: :grin: :evil: :cry: :cool: :arrow: :???: :?: :!:

ИТ Проффи

Сообщить об опечатке

Текст, который будет отправлен нашим редакторам: