воскресенье, 8 февраля 2009 г.

Перенаправление стандартных потоков данных в Linux

Виртуальная энциклопедия "Linux по-русски": новости, статьи, ссылки на материалы по операционной системе GNU/Linux.

Алексей Дмитриев, февраль 2009.

Введение

Прежде чем заводить речь о перенаправлениях, нужно представлять себе работу процесса в Юниксовидных ОС. Вдаваться во внутреннюю структуру процесса не входит в наши намерения, мы будем рассматривать процесс как некий "черный ящик", а лучше завод, перерабатывающий данные.

Наблюдая за заводом извне, мы замечаем три потока:

  • 0. На территорию завода поступает входящий поток "сырья" - данных подлежащих переработке.
  • 1. Из ворот выходит поток продукции - данных, подвергшихся переработке на заводе-процессе.
  • 2. Из трубы поднимается дым, по виду которого можно судить о работе завода. Если дыма не заметно, то завод работает нормально (у нас ведь экологически чистое производство информации). Если вдруг повалил густой дым, то, ясное дело, что-то не в порядке.

На компьютерном языке эти три потока данных называются стандартными потоками. Каждый имеет числовой дескриптор (номер), название и направление по умолчанию.

Дескриптор 0: Входящий стандартный поток (Standart Input, stdin). По умолчанию, поступает со стандартного устройства ввода (обычно с клавиатуры).

Дескриптор 1: Выходящий стандартный поток (Standar Output, stdout). По умолчанию направляется на стандартное устройство вывода (обычно экран монитора).

Дескриптор 2: Стандартный поток сообщений об ошибках (Standart Error, stderr). С английского переводится как "стандартная ошибка", но в русском языке такое выражение звучит двусмысленно. Поэтому я предпочитаю называть его стандартным сообщением, тем более, что в большинстве случаев оно сообщает не об ошибке, а о ходе процесса. По умолчанию направляется туда же, куда и стандартный вывод - на экран монитора, но не смешивается со стандартным выводом, а раскладывается по разным "полкам".

Входящий поток, показан зеленым, имеет дескриптор 0
Выходящий поток, показан красным, имеет дескриптор 1
Поток сообщений, показан синим, имеет дескриптор 2

Вот пример стандартного ввода и вывода:

$ echo стандарный ввод   (Enter)  стандарный ввод 

Команда echo направляет поток данных с клавиатуры на экран дисплея.

А вот пример стандартного сообщения об ошибке:

$ cat file.txt  cat: file.txt: Нет такого файла или каталога 

Каждый из этих стандартных потоков можно перенаправлять, то есть направлять не туда, куда поток направляется по умолчанию. Это и есть перенаправление.

Перенаправление стандартного вывода

Во многих случаях удобнее работать не со стандартным выводом на монитор, а с файлами. Файлы можно сохранять, редактировать, посылать по почте, и т.д. Мы всегда можем перенаправить вывод команды в файл, применив оператор перенаправления > и указав имя файла. При этом не важно, существует ли такой файл на самом деле. Если такого файла нет, то он будет создан, а если есть, то перезаписан (все прежнее содержимое будет стерто, а новое записано).

$ echo стандарный ввод > ввод.txt

Как видите, на экране не появились слова "стандартный ввод", зато в текущей директории появился файл ввод.txt с этими словами.

Можно дописать в файл ввод.txt вывод других команд, не уничтожая имеющегося содержимого. Для этого служит оператор >>

$ echo и стандарный вывод >> ввод.txt

Проделайте этот опыт самостоятельно, чтобы убедиться, что это так. Для определения текущей директории применяется команда pwd:

$ pwd  /home/ваш_логин/ 

Это я на случай, если вы не сразу найдете файл ввод.txt. (pwd расшифровывается как "print working directory" - "сообщить рабочую директорию").

Внимание: Следите за тем, в какой директории вы находитесь и без надобности не перенаправляйте вывод в существующие файлы. Могут быть уничтожены важные файлы (особенно, если вы имеете дурную привычку работать под логином администратора - root'а).

Перенаправление ввода

Не все команды принимают файлы в качестве аргумента; некоторые принимают данные только из стандартного ввода.

Например, команда tr, которая служит для перевода (замены) выбранных символов в другие символы или удаления их.

На этот случай служит оператор перенаправления ввода < .

$ tr [a-z] [A-Z] < case.txt  TRANSLATION LOWER CASE INTO UPPERCASE 

В файле case.txt содержался тот же текст, только написанный строчными буквами.

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

$ tr [a-z] [A-Z] < case.txt > case-upper.txt

Появится файл case-upper.txt, содержащий только что виденный нами текст.

И, наконец, можно дописать изменения текста в исходный файл:

$ tr [a-z] [A-Z] < case.txt >> case.txt

А вот пытаться переписать исходный файл измененным текстом не получится - будут утеряны и исходный файл и результат изменений:

$ tr [a-z] [A-Z] < case.txt > case.txt

Попробуйте сами...

Перенаправление стандартного потока сообщений

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

Например, команда wc, которая подсчитывает количество строк, слов, байт, или символов, работает только с текстовыми файлами (кроме опции -с). Если среди заданных команде для обработки файлов попадутся бинарные или .html файлы, то команда выдаст множество сообщений. Зададим команде wc просчитать все файлы в текущей директории (при помощи символа астериска - *)

$ wc *  wc: Documents: Is a directory       0       0       0 Documents       9      14     207 MyComputer.desktop     310    1963   12555 bookindx.txt       2       5      39 case-upper.txt       2       5      38 case.txt wc: mill.gif:1: Invalid or incomplete multibyte or wide character wc: mill.gif:2: Invalid or incomplete multibyte or wide character wc: mill.gif:3: Invalid or incomplete multibyte or wide character wc: mill.gif:4: Invalid or incomplete multibyte or wide character wc: mill.gif:5: Invalid or incomplete multibyte or wide character wc: mill.gif:6: Invalid or incomplete multibyte or wide character     73     307   12702 mill.gif     119     745    9468 redirections_and_pipes.txt wc: sed.html:53: Invalid or incomplete multibyte or wide character     2732   14592  167105 sed.html     682    4198   29314 sed_mcmahon.txt     114     156    1715 shema.txt     150     318    5066 trash.desktop      15      18     258 Дисковод       1       0       2 Текстовый файл    4209   22321  238469 итого 

Строки вывода, начинающиеся с wc: являются сообщениями. На самом деле этих сообщений было намного больше, мне пришлось уменьшить их количество, чтобы не загромождать статью.

Избавиться от них очень просто: нужно воспользоваться тем же оператором перенаправления (>), предварив его номером перенаправляемого потока. Стандартный поток сообщений имеет дескриптор (номер) 2, вот и поставим двойку перед оператором перенаправления - 2> . Куда же перенаправить этот поток? Можно перенаправить в какой-нибудь файл, если хотите на досуге разобраться с этими сообщениями. (Например, при компиляции программ выдается множество сообщений, которые вовсе не бессмысленны). А если сообщения вам не нужны, то лучше перенаправить их в файл /dev/null. Это специальный файл, который принимает любое количество данных и обращает их в ничто - эдакая бездонная и безвозвратная мусорная корзина, а лучше - "черная дыра". Вот в нее то и направим ненужный поток сообщений:

$ wc * 2> /dev/null       0       0       0 Documents       9      14     207 MyComputer.desktop     310    1963   12555 bookindx.txt       2       5      39 case-upper.txt       2       5      38 case.txt      73     307   12702 mill.gif     119     745    9468 redirections_and_pipes.txt    2732   14592  167105 sed.html     682    4198   29314 sed_mcmahon.txt     114     156    1715 shema.txt     150     318    5066 trash.desktop      15      18     258 Дисковод       1       0       2 Текстовый файл    4209   22321  238469 итого 

В итоге получаем на экране только вывод программы.

Возникает резонный вопрос: "А можно ли прочитать на экране только сообщения, а вывод программы перенаправить в файл?". Конечно можно:

$ wc * 1> /dev/null

а, принимая во внимание, что перенаправляется по умолчанию только стандартный вывод (поток номер 1), то единичку перед оператором перенаправления ставить ни к чему, результат будет один:

$ wc * > /dev/null  wc: Documents: Is a directory wc: mill.gif:1: Invalid or incomplete multibyte or wide character wc: mill.gif:2: Invalid or incomplete multibyte or wide character wc: mill.gif:3: Invalid or incomplete multibyte or wide character ... 

Существует также возможность перенаправить потоки 1 и 2 в разные файлы:

$ wc * > wc.txt 2> /dev/null

Убедитесь сами, что файл wc.txt не содержит стандартных сообщений.

И последняя хитрость. Можно направить оба выходных потока: стандарный вывод и стандартное сообщение в один и тот же файл, так, чтобы в файле сохранить все, что мы увидели бы на экране монитора:

$ wc * > wc.txt 2>&1

Первый оператор перенаправления направляет стандартный вывод в файл, а второй оператор перенаправления указывает, что стандартное сообщение следует направить туда же, куда и поток номер 1.

Заключение

Перенаправление стандартных потоков широко применяется при работе в командной строке. Кроме очевидной потребности сохранять результаты работы различных команд в файлах, перенаправление позволяет избавиться от ненужных сообщений, задавать командам данные из файлов, автоматизировать рутинные задачи.

Комментариев нет: