.$redefine CHAPTER=shell .$redefine SECTION=redir .$redefine TITLE=Перенаправление ввода/вывода .+ section.inchtml .$redefine SEC_JUMPER=^(RELS_PTN intro,grep) .+ section_begin.inchtml ^(|BEGIN_PAGE Перенаправление вывода команд в файл)

Представим себе ситуацию: хочется посмотреть листинг директории /bin (в которой лежат многие программы). Выполняем команду "ls -l /bin" и... Результат в экран не помещается. А ведь бывают директории еще большего объема. Что делать?

Большинство команд выводят информацию на терминал, а некоторые (например, текстовый редактор) вводят данные с терминала. В Unix есть почти универсальное правило: терминал может быть заменен для ввода, вывода или и того, и другого, на файл.

Так, чтобы сохранить вывод нашей команды в файл, надо написать: ^(BEGIN_EXAMPLE) bobby:~% ls -l /bin >filelist bobby:~% ^(END_EXAMPLE)

При этом весь вывод команды ls будет вместо терминала отправлен в файл. Символ ">" означает, что выходной поток должен быть помещен в указанный далее файл, а не выведен на терминал. Если в файле что-то было, то старое содержимое будет стерто.

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

Еще один пример: можно слить содержимое нескольких файлов в один файл, "перехватив" выходной поток команды cat и отправив его в файл: ^(BEGIN_EXAMPLE) bobby:~% cat file1 file2 file3 >all bobby:~% _ ^(END_EXAMPLE)

Сделать то же самое при помощи команды cp нельзя: ^(BEGIN_EXAMPLE) bobby:~% cp file1 file2 file3 all cp: copying multiple files, but last argument (all) is not a directory Try `cp --help' for more information. bobby:~% _ ^(END_EXAMPLE)

Символ ">>" действует подобно ">", но указывает на необходимость добавить выходной поток к концу файла, вместо того, чтобы стереть старое содержимое. Например: ^(BEGIN_EXAMPLE) bobby:~% cat file1 >all bobby:~% cat file2 file3 >>all bobby:~% _ ^(END_EXAMPLE)

Первая команда cat скопирует содержимое file1 в all, а вторая -- допишет к нему содержимое file2 и file3.

Использование ">>" очень удобно, если есть некий "долгоживущий" файл (например, протокол каких-то действий или результатов), к которому иногда надо дописывать данные в конец. Просто указать ">>" с какой-нибудь командой обычно намного быстрее, чем загружать файл в текстовый редактор и что-то дописывать. ^(END_PAGE) ^(|BEGIN_PAGE Конвейеры)

Теперь вернемся к нашему первому примеру: как посмотреть листинг большой директории. Мы отправили вывод команды ls в файл, а потом запустили less для его просмотра. Сам же временный файл не имеет никакого смысла -- потом он больше не нужен.

Можно обойтись без временного файла, воспользовавшись конвейером: ^(BEGIN_EXAMPLE) bobby:~% ls -l /bin | less ^(END_EXAMPLE)

Символ "|" означает, что надо взять выходной поток от первой команды, и отправить его на входной поток второй.

Большинство команд, выдающих информацию из файла на экран (cat, more, less) устроены так, что они будут читать входной поток, если не указан никакой файл -- вот почему less показывает то, что ему "пришло" от ls. ^(BEGIN_NOTE) В отличие от Dos, где тоже поддерживаются операторы перенаправления ввода/вывода, в Unix команды в конвейере запускаются одновременно, и данные передаются через программный канал (это специальное средство, предоставляемое ядром Unix) сразу от одной программы к другой, а не через скрытый временный файл. ^(END_NOTE)

Можно заставить команду читать вместо терминала не только выходной поток другой команды, но и обычный файл. Это делается при помощи оператора "<", который указывает, что вместо терминала надо брать входной поток из указанного далее файла. Пример (команда "sort" построчно сортирует входные данные): ^(BEGIN_EXAMPLE) bobby:~% cat proverbs What is worth doing, is worth doing well. Art is long, life is short. History repeats itself. Dead men tell no tales. _______________________ bobby:~% sort <proverbs Art is long, life is short. Dead men tell no tales. History repeats itself. What is worth doing, is worth doing well. _______________________ bobby:~% _ ^(END_EXAMPLE) ^(END_PAGE) ^(|BEGIN_PAGE Поток сообщений об ошибках)

Что будет, если мы попросим ls показать файлы, которых нет? ^(BEGIN_EXAMPLE) bobby:~% ls -l file1 file2 file10 file11 /bin/ls: file10: No such file or directory /bin/ls: file11: No such file or directory -rw-r--r-- 1 ivanov lab5 76 Feb 21 13:23 file1 -rw-r--r-- 1 ivanov lab5 32 Feb 21 13:23 file2 bobby:~% _ ^(END_EXAMPLE)

Файлы которые есть, ls покажет, а про остальные скажет, что их нет. А теперь перенаправим вывод ls в файл: ^(BEGIN_EXAMPLE) bobby:~% ls -l file1 file2 file10 file11 >filelist /bin/ls: file10: No such file or directory /bin/ls: file11: No such file or directory bobby:~% _ ^(END_EXAMPLE)

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

А дело в том, что кроме выходного потока есть еще поток сообщений об ошибках, и "культурно" написанные программы все "ругательства" отправляют туда. Чтобы перенаправить в файл поток сообщений об ошибках (обычно его сокращенно называют stderr), надо перед символом ">" указать номер потока -- 2. Пример: ^(BEGIN_EXAMPLE) bobby:~% ls -l file1 file2 file10 file11 >filelist 2>errs bobby:~% cat filelist -rw-r--r-- 1 ivanov lab5 76 Feb 21 13:23 file1 -rw-r--r-- 1 ivanov lab5 32 Feb 21 13:23 file2 bobby:~% cat errs /bin/ls: file10: No such file or directory /bin/ls: file11: No such file or directory bobby:~% _ ^(END_EXAMPLE) ^(BEGIN_NOTE) Такое перенаправление потока stderr невозможно в оболочках csh и tcsh -- в них для этого используется другой, более запутанный синтаксис. ^(END_NOTE) ^(BEGIN_NOTE) Те, кто программировал на языке C, знают, что там есть три стандартных файловых потока для ввода/вывода: stdin (входной поток, дескриптор 0), stdout (выходной поток, дескриптор 1) и stderr (поток сообщений об ошибках, дескриптор 2). Операторы ">", "<" и "2>" перенаправляют именно эти потоки. ^(END_NOTE)

С потоком stderr обычно требуется сделать одну из трех вещей: перенаправить его туда же, куда и выходной поток, направить в отдельный файл, или отправить "в никуда". В первом случае можно воспользоваться специальной формой оператора перенаправления вывода -- "2>&1" ("отправь второй поток (stderr) туда же, куда и первый (stdout)): ^(BEGIN_EXAMPLE) bobby:~% ls -l file1 file2 file10 file11 >filelist 2>&1 bobby:~% cat filelist /bin/ls: file10: No such file or directory /bin/ls: file11: No such file or directory -rw-r--r-- 1 ivanov lab5 76 Feb 21 13:23 file1 -rw-r--r-- 1 ivanov lab5 32 Feb 21 13:23 file2 bobby:~% _ ^(END_EXAMPLE)

Этот способ работает и тогда, когда стандартный вывод отправляется по конвейеру другой программе.

Во третьем же случае надо отправить stderr в "черную дыру" -- файл /dev/null: ^(BEGIN_EXAMPLE) bobby:~% ls -l file1 file2 file10 file11 >filelist 2>/dev/null bobby:~% cat filelist -rw-r--r-- 1 ivanov lab5 76 Feb 21 13:23 file1 -rw-r--r-- 1 ivanov lab5 32 Feb 21 13:23 file2 bobby:~% _ ^(END_EXAMPLE) ^(END_PAGE) ^(BEGIN_PAGE Какие еще есть операторы перенаправления ввода/вывода?)

Подробную информацию на эту тему можно найти в info-документации на zsh, набрав команду "info zsh redirection".

Здесь же следует лишь заметить, что zsh обладает способностью перенаправлять вывод в несколько файлов сразу. Это бывает полезно, если хочется запустить какую-нибудь "долгоиграющую" команду так, чтобы ее вывод сохранялся в файле, но при этом отображался бы и на экране -- для этого надо перенаправить вывод одновременно в файл "протокола" и в файл /dev/tty. ^(END_PAGE) .+ section_end.inchtml