Перенаправление вывода в файл. Перенаправление ввода и вывода
Вы уже знакомы с двумя методами работы с тем, что выводят сценарии командной строки:
- Отображение выводимых данных на экране.
- Перенаправление вывода в файл.
Стандартные дескрипторы файлов
Всё в Linux - это файлы, в том числе - ввод и вывод. Операционная система идентифицирует файлы с использованием дескрипторов.Каждому процессу позволено иметь до девяти открытых дескрипторов файлов. Оболочка bash резервирует первые три дескриптора с идентификаторами 0, 1 и 2. Вот что они означают.
- 0 , STDIN - стандартный поток ввода.
- 1 , STDOUT - стандартный поток вывода.
- 2 , STDERR - стандартный поток ошибок.
Вам нужно как следует разобраться в стандартных потоках. Их можно сравнить с фундаментом, на котором строится взаимодействие скриптов с внешним миром. Рассмотрим подробности о них.
STDIN
STDIN - это стандартный поток ввода оболочки. Для терминала стандартный ввод - это клавиатура. Когда в сценариях используют символ перенаправления ввода - < , Linux заменяет дескриптор файла стандартного ввода на тот, который указан в команде. Система читает файл и обрабатывает данные так, будто они введены с клавиатуры.Многие команды bash принимают ввод из STDIN , если в командной строке не указан файл, из которого надо брать данные. Например, это справедливо для команды cat .
Когда вы вводите команду cat в командной строке, не задавая параметров, она принимает ввод из STDIN . После того, как вы вводите очередную строку, cat просто выводит её на экран.
STDOUT
STDOUT - стандартный поток вывода оболочки. По умолчанию это - экран. Большинство bash-команд выводят данные в STDOUT , что приводит к их появлению в консоли. Данные можно перенаправить в файл, присоединяя их к его содержимому, для этого служит команда >> .Итак, у нас есть некий файл с данными, к которому мы можем добавить другие данные с помощью этой команды:
Pwd >> myfile
То, что выведет pwd , будет добавлено к файлу myfile , при этом уже имеющиеся в нём данные никуда не денутся.
Перенаправление вывода команды в файл
Пока всё хорошо, но что если попытаться выполнить что-то вроде показанного ниже, обратившись к несуществующему файлу xfile , задумывая всё это для того, чтобы в файл myfile попало сообщение об ошибке.
Ls –l xfile > myfile
После выполнения этой команды мы увидим сообщения об ошибках на экране.
Попытка обращения к несуществующему файлу
При попытке обращения к несуществующему файлу генерируется ошибка, но оболочка не перенаправила сообщения об ошибках в файл, выведя их на экран. Но мы-то хотели, чтобы сообщения об ошибках попали в файл. Что делать? Ответ прост - воспользоваться третьим стандартным дескриптором.
STDERR
STDERR представляет собой стандартный поток ошибок оболочки. По умолчанию этот дескриптор указывает на то же самое, на что указывает STDOUT , именно поэтому при возникновении ошибки мы видим сообщение на экране.Итак, предположим, что надо перенаправить сообщения об ошибках, скажем, в лог-файл, или куда-нибудь ещё, вместо того, чтобы выводить их на экран.
▍Перенаправление потока ошибок
Как вы уже знаете, дескриптор файла STDERR - 2. Мы можем перенаправить ошибки, разместив этот дескриптор перед командой перенаправления:Ls -l xfile 2>myfile
cat ./myfile
Сообщение об ошибке теперь попадёт в файл myfile .
Перенаправление сообщения об ошибке в файл
▍Перенаправление потоков ошибок и вывода
При написании сценариев командной строки может возникнуть ситуация, когда нужно организовать и перенаправление сообщений об ошибках, и перенаправление стандартного вывода. Для того, чтобы этого добиться, нужно использовать команды перенаправления для соответствующих дескрипторов с указанием файлов, куда должны попадать ошибки и стандартный вывод:Ls –l myfile xfile anotherfile 2> errorcontent 1> correctcontent
Перенаправление ошибок и стандартного вывода
Оболочка перенаправит то, что команда ls обычно отправляет в STDOUT , в файл correctcontent благодаря конструкции 1> . Сообщения об ошибках, которые попали бы в STDERR , оказываются в файле errorcontent из-за команды перенаправления 2> .
Если надо, и STDERR , и STDOUT можно перенаправить в один и тот же файл, воспользовавшись командой &> :
Перенаправление STDERR и STDOUT в один и тот же файл
После выполнения команды то, что предназначено для STDERR и STDOUT , оказывается в файле content .
Перенаправление вывода в скриптах
Существует два метода перенаправления вывода в сценариях командной строки:- Временное перенаправление, или перенаправление вывода одной строки.
- Постоянное перенаправление, или перенаправление всего вывода в скрипте либо в какой-то его части.
▍Временное перенаправление вывода
В скрипте можно перенаправить вывод отдельной строки в STDERR . Для того, чтобы это сделать, достаточно использовать команду перенаправления, указав дескриптор STDERR , при этом перед номером дескриптора надо поставить символ амперсанда (&): #!/bin/bash
echo "This is an error" >&2
echo "This is normal output"
Если запустить скрипт, обе строки попадут на экран, так как, как вы уже знаете, по умолчанию ошибки выводятся туда же, куда и обычные данные.
Временное перенаправление
Запустим скрипт так, чтобы вывод STDERR попадал в файл.
./myscript 2> myfile
Как видно, теперь обычный вывод делается в консоль, а сообщения об ошибках попадают в файл.
Сообщения об ошибках записываются в файл
▍Постоянное перенаправление вывода
Если в скрипте нужно перенаправлять много выводимых на экран данных, добавлять соответствующую команду к каждому вызову echo неудобно. Вместо этого можно задать перенаправление вывода в определённый дескриптор на время выполнения скрипта, воспользовавшись командой exec: #!/bin/bash
exec 1>outfile
echo "This is a test of redirecting all output"
echo "from a shell script to another file."
echo "without having to redirect every line"
Запустим скрипт.
Перенаправление всего вывода в файл
Если просмотреть файл, указанный в команде перенаправления вывода, окажется, что всё, что выводилось командами echo , попало в этот файл.
Команду exec можно использовать не только в начале скрипта, но и в других местах:
#!/bin/bash
exec 2>myerror
echo "This is the start of the script"
echo "now redirecting all output to another location"
exec 1>myfile
echo "This should go to the myfile file"
echo "and this should go to the myerror file" >&2
Вот что получится после запуска скрипта и просмотра файлов, в которые мы перенаправляли вывод.
Перенаправление вывода в разные файлы
Сначала команда exec задаёт перенаправление вывода из STDERR в файл myerror . Затем вывод нескольких команд echo отправляется в STDOUT и выводится на экран. После этого команда exec задаёт отправку того, что попадает в STDOUT , в файл myfile , и, наконец, мы пользуемся командой перенаправления в STDERR в команде echo , что приводит к записи соответствующей строки в файл myerror.
Освоив это, вы сможете перенаправлять вывод туда, куда нужно. Теперь поговорим о перенаправлении ввода.
Перенаправление ввода в скриптах
Для перенаправления ввода можно воспользоваться той же методикой, которую мы применяли для перенаправления вывода. Например, команда exec позволяет сделать источником данных для STDIN какой-нибудь файл:Exec 0< myfile
Эта команда указывает оболочке на то, что источником вводимых данных должен стать файл myfile , а не обычный STDIN . Посмотрим на перенаправление ввода в действии:
#!/bin/bash
exec 0< testfile
count=1
while read line
do
echo "Line #$count: $line"
count=$(($count + 1))
done
Вот что появится на экране после запуска скрипта.
Перенаправление ввода
В одном из предыдущих материалов вы узнали о том, как использовать команду read для чтения данных, вводимых пользователем с клавиатуры. Если перенаправить ввод, сделав источником данных файл, то команда read , при попытке прочитать данные из STDIN , будет читать их из файла, а не с клавиатуры.
Некоторые администраторы Linux используют этот подход для чтения и последующей обработки лог-файлов.
Создание собственного перенаправления вывода
Перенаправляя ввод и вывод в сценариях, вы не ограничены тремя стандартными дескрипторами файлов. Как уже говорилось, можно иметь до девяти открытых дескрипторов. Остальные шесть, с номерами от 3 до 8, можно использовать для перенаправления ввода или вывода. Любой из них можно назначить файлу и использовать в коде скрипта.Назначить дескриптор для вывода данных можно, используя команду exec:
#!/bin/bash
exec 3>myfile
echo "This should display on the screen"
echo "and this should be stored in the file" >&3
echo "And this should be back on the screen"
После запуска скрипта часть вывода попадёт на экран, часть - в файл с дескриптором 3 .
Перенаправление вывода, используя собственный дескриптор
Создание дескрипторов файлов для ввода данных
Перенаправить ввод в скрипте можно точно так же, как и вывод. Сохраните STDIN в другом дескрипторе, прежде чем перенаправлять ввод данных.После окончания чтения файла можно восстановить STDIN и пользоваться им как обычно:
#!/bin/bash
exec 6<&0
exec 0< myfile
count=1
while read line
do
echo "Line #$count: $line"
count=$(($count + 1))
done
exec 0<&6
read -p "Are you done now? " answer
case $answer in
y) echo "Goodbye";;
n) echo "Sorry, this is the end.";;
esac
Испытаем сценарий.
Перенаправление ввода
В этом примере дескриптор файла 6 использовался для хранения ссылки на STDIN . Затем было сделано перенаправление ввода, источником данных для STDIN стал файл. После этого входные данные для команды read поступали из перенаправленного STDIN , то есть из файла.
После чтения файла мы возвращаем STDIN в исходное состояние, перенаправляя его в дескриптор 6 . Теперь, для того, чтобы проверить, что всё работает правильно, скрипт задаёт пользователю вопрос, ожидает ввода с клавиатуры и обрабатывает то, что введено.
Закрытие дескрипторов файлов
Оболочка автоматически закрывает дескрипторы файлов после завершения работы скрипта. Однако, в некоторых случаях нужно закрывать дескрипторы вручную, до того, как скрипт закончит работу. Для того, чтобы закрыть дескриптор, его нужно перенаправить в &- . Выглядит это так: #!/bin/bash
exec 3> myfile
echo "This is a test line of data" >&3
exec 3>&-
echo "This won"t work" >&3
После исполнения скрипта мы получим сообщение об ошибке.
Попытка обращения к закрытому дескриптору файла
Всё дело в том, что мы попытались обратиться к несуществующему дескриптору.
Будьте внимательны, закрывая дескрипторы файлов в сценариях. Если вы отправляли данные в файл, потом закрыли дескриптор, потом - открыли снова, оболочка заменит существующий файл новым. То есть всё то, что было записано в этот файл ранее, будет утеряно.
Получение сведений об открытых дескрипторах
Для того, чтобы получить список всех открытых в Linux дескрипторов, можно воспользоваться командой lsof . Во многих дистрибутивах, вроде Fedora, утилита lsof находится в /usr/sbin . Эта команда весьма полезна, так как она выводит сведения о каждом дескрипторе, открытом в системе. Сюда входит и то, что открыли процессы, выполняемые в фоне, и то, что открыто пользователями, вошедшими в систему.У этой команды есть множество ключей, рассмотрим самые важные.
- -p Позволяет указать ID процесса.
- -d Позволяет указать номер дескриптора, о котором надо получить сведения.
Ключ -a используется для выполнения операции логического И над результатами, возвращёнными благодаря использованию двух других ключей:
Lsof -a -p $$ -d 0,1,2
Вывод сведений об открытых дескрипторах
Тип файлов, связанных с STDIN , STDOUT и STDERR - CHR (character mode, символьный режим). Так как все они указывают на терминал, имя файла соответствует имени устройства, назначенного терминалу. Все три стандартных файла доступны и для чтения, и для записи.
Посмотрим на вызов команды lsof из скрипта, в котором открыты, в дополнение к стандартным, другие дескрипторы:
#!/bin/bash
exec 3> myfile1
exec 6> myfile2
exec 7< myfile3
lsof -a -p $$ -d 0,1,2,3,6,7
Вот что получится, если этот скрипт запустить.
Просмотр дескрипторов файлов, открытых скриптом
Скрипт открыл два дескриптора для вывода (3 и 6) и один - для ввода (7). Тут же показаны и пути к файлам, использованных для настройки дескрипторов.
Подавление вывода
Иногда надо сделать так, чтобы команды в скрипте, который, например, может исполняться как фоновый процесс, ничего не выводили на экран. Для этого можно перенаправить вывод в /dev/null . Это - что-то вроде «чёрной дыры».Вот, например, как подавить вывод сообщений об ошибках:
Ls -al badfile anotherfile 2> /dev/null
Тот же подход используется, если, например, надо очистить файл, не удаляя его:
Cat /dev/null > myfile
Итоги
Сегодня вы узнали о том, как в сценариях командной строки работают ввод и вывод. Теперь вы умеете обращаться с дескрипторами файлов, создавать, просматривать и закрывать их, знаете о перенаправлении потоков ввода, вывода и ошибок. Всё это очень важно в деле разработки bash-скриптов.В следующий раз поговорим о сигналах Linux, о том, как обрабатывать их в сценариях, о запуске заданий по расписанию и о фоновых задачах.
Уважаемые читатели! В этом материале даны основы работы с потоками ввода, вывода и ошибок. Уверены, среди вас есть профессионалы, которые могут рассказать обо всём этом то, что приходит лишь с опытом. Если так - передаём слово вам.
Для того, чтобы записать данные в файл или прочитать их оттуда, процессу необходимо сначала открыть этот файл (при открытии на запись, возможно, придётся предварительно создать его). При этом процесс получает дескриптор (описатель) открытого файла - уникальное для этого процесса число, которое он и будет использовать во всех операциях записи. Первый открытый файл получит дескриптор, второй - 1 и так далее. Закончив работу с файлом, процесс закрывает его, при этом дескриптор освобождается и может быть использован повторно. Если процесс завершается, не закрыв файлы, за него это делает система. Строго говоря, только в операции открытия дескриптора указывается, какой именно файл будет использоваться. В качестве «файла» используются и обычные файлы, и файлы-дырки (чаще всего - терминалы), и каналы , описанные в разделе Pipeline..Конвейер. Дальнейшие операции - чтение, запись и закрытие, работают с дескриптором, как с потоком данных , а куда именно ведёт этот поток, неважно.
Каждый процесс Linux получает при старте три «файла», открытых для него системой. Первый из них (дескриптор) открыт на чтение , это стандартный ввод процесса. Именно со стандартным вводом работают все операции чтения, если в них не указан дескриптор файла. Второй (дескриптор 1) - открыт на запись, это стандартный вывод процесса. С ним работают все операции записи, если дескриптор файла не указан в них явно. Наконец, третий поток данных (дескриптор 2) предназначается для вывода диагностических сообщений, он называется стандартный вывод ошибок . Поскольку эти три дескриптора уже открыты к моменту запуска процесса, первый файл, открытый самим процессом, будет, скорее всего, иметь дескриптор 3 .
Дескриптор Описатель потока данных, открытого процессом. Дескрипторы нумеруются начиная с. При открытии нового потока данных его дескриптор получает наименьший из неиспользуемых в этот момент номеров. Три заранее открытых дескриптора: стандартный ввод (), стандартный вывод (1) и стандартный вывод ошибок (2) процессу выдаются при запуске.
Механизм копирования окружения , описанный в лекции , подразумевает, в числе прочего, копирование всех открытых дескрипторов родительского процесса дочернему. В результате, и родительский, и дочерний процесс имеют под одинаковыми дескрипторами одни и те же потоки данных. Когда запускается стартовый командный интерпретатор , все три заранее открытых дескриптора связаны у него с терминалом (точнее, с соответствующим файлом-дыркой типа tty): пользователь вводит команды с клавиатуры и видит сообщения на экране. Следовательно, любая команда, запускаемая из командной оболочки, будет выводить на тот же терминал, а любая команда, запущенная интерактивно (не в фоне) - вводить оттуда.
Стандартный вывод
Мефодий уже сталкивался с тем, что некоторые программы умеют выводить не только на терминал, но и в файл, например, info при указании параметрического ключа « -o » с именем файла выведет текст руководства в файл, вместо того, чтобы отображать его на мониторе. Даже если разработчиками программы не предусмотрен такой ключ, Мефодию известен и другой способ сохранить вывод программы в файле вместо того, чтобы выводить его на монитор: поставить знак « > » и указать после него имя файла. Таким образом Мефодий уже создавал короткие текстовые файлы (сценарии) при помощи утилиты cat (см. лекцию Доступ процессов к файлам и каталогам).
$ cat > textfile Это файл для примеров. ^D $ ls -l textfile -rw-r--r-- 1 methody methody 23 Ноя 15 16:06 textfile
Пример 2 . Перенаправление стандартного вывода в файл
От использования символа « > » возможности самой утилиты cat , конечно, не расширились. Более того, cat в этом примере не получила от командной оболочки никаких параметров: ни знака « > », ни последующего имени файла. В этом случае cat работала как обычно, не зная (и даже не интересуясь!), куда попадут выведенные данные: на экран монитора, в файл или куда-нибудь ещё. Вместо того, чтобы самой обеспечивать доставку вывода до конечного адресата (будь то человек или файл), cat отправляет все данные на стандартный вывод (сокращённо - stdout).
Подмена стандартного вывода - задача командной оболочки (shell). В данном примере shell создаёт пустой файл, имя которого указано после знака « > », и дескриптор этого файла передаётся программе cat под номером 1 (стандартный вывод ). Делается это очень просто. В лекции Доступ процессов к файлам и каталогам было рассказано о том, как запускаются команды из оболочки. В частности, после выполнения fork() появляется два одинаковых процесса, один из которых - дочерний - должен запустить вместо себя команду (выполнить exec()). Так вот, перед этим он закрывает стандартный вывод (дескриптор 1 освобождается) и открывает файл (с ним связывается первый свободный дескриптор, т. е. 1), а запускаемой команде ничего знать и не надо: её стандартный вывод уже подменён. Эта операция называется перенаправлением стандартного вывода. В том случае, если файл уже существует, shell запишет его заново, полностью уничтожив всё, что в нём содержалось до этого. Поэтому Мефодию, чтобы продолжить записывать данные в textfile , потребуется другая операция - « >> ».
$ cat >> textfile Пример 1. ^D $ cat textfile Это файл для примеров. Пример 1. $
Пример 3 . Недеструктивное перенаправление стандартного вывода
Мефодий получил именно тот результат, который ему требовался: добавил в конец уже существующего файла данные со стандартного вывода очередной команды.
Стандартный вывод Поток данных, открываемый системой для каждого процесса в момент его запуска, и предназначенный для данных, выводимых процессом.
Стандартный ввод
Аналогичным образом для передачи данных на вход программе может быть использован стандартный ввод (сокращённо - stdin). При работе с командной строкой стандартный ввод - это символы, вводимые пользователем с клавиатуры. Стандартный ввод можно перенаправить при помощи командной оболочки, подав на него данные из некоторого файла. Символ « < » служит для перенаправления содержимого файла на стандартный ввод программе. Например, если вызвать утилиту sort без параметра, она будет читать строки со стандартного ввода. Команда « sort < имя_файла » подаст на ввод sort данные из файла.
$ sort < textfile Пример 1. Это файл для примеров. $
Пример 4 . Перенаправление стандартного ввода из файла
Результат действия этой команды совершенно аналогичен команде sort textfile , разница в том, что когда используется « < », sort получает данные со стандартного ввода, ничего не зная о файле « textfile », откуда они поступают. Механизм работы shell в данном случае тот же, что и при перенаправлении вывода: shell читает данные из файла « textfile », запускает утилиту sort и передаёт ей на стандартный ввод содержимое файла.
Стоит помнить, что операция « > » деструктивна : она всегда создаёт файл нулевой длины. Поэтому для, допустим, сортировки данных в файле надо применять последовательно sort < файл > новый_файл и mv новый_файл файл . Команда вида команда < файл > тот_же_файл просто урежет его до нулевой длины!
Стандартный ввод Поток данных, открываемый системой для каждого процесса в момент его запуска, и предназначенный для ввода данных.
Стандартный вывод ошибок
В качестве первого примера и упражнения на перенаправление Мефодий решил записать руководство по cat в свой файл cat.info:
$ info cat > cat.info info: Запись ноды (coreutils.info.bz2)cat invocation... info: Завершено. $ head -1 cat.info File: coreutils.info, Node: cat invocation, Next: tac invocation, Up: Output of entire files $
Пример 5 . Стандартный вывод ошибок
Удивлённый Мефодий обнаружил, что вопреки его указанию отправляться в файл две строки, выведенные командой info , всё равно проникли на терминал. Очевидно, эти строки не попали на стандартный вывод потому, что не относятся непосредственно к руководству, которое должна вывести программа, они информируют пользователя о ходе выполнения работы: записи руководства в файл. Для такого рода диагностических сообщений , а также для сообщений об ошибках, возникших в ходе выполнения программы, в Linux предусмотрен стандартный вывод ошибок (сокращённо - stderr).
Стандартный вывод ошибок Поток данных, открываемый системой для каждого процесса в момент его запуска, и предназначенный для диагностических сообщений , выводимых процессом.
Использование стандартного вывода ошибок наряду со стандартным выводом позволяет отделить собственно результат работы программы от разнообразной сопровождающей информации, например, направив их в разные файлы. Стандартный вывод ошибок может быть перенаправлен так же, как и стандартный ввод/вывод, для этого используется комбинация символов « 2 ».
$ info cat > cat.info 2> cat.stderr $ cat cat.stderr info: Запись ноды (coreutils.info.bz2)cat invocation... info: Завершено. $
Пример 6 . Перенаправление стандартного вывода ошибок
В этот раз на терминал уже ничего не попало, стандартный вывод отправился в файл cat.info , стандартный вывод ошибок - в cat.stderr . Вместо « > » и « 2 » Мефодий мог бы написать « 1> » и « 2> ». Цифры в данном случае обозначают номера дескрипторов открываемых файлов. Если некая утилита ожидает получить открытый дескриптор с номером, допустим, 4 , то чтобы её запустить обязательно потребуется использовать сочетание « 4> ».
Иногда, однако, требуется объединить стандартный вывод и страндартный вывод ошибок в одном файле, а не разделять их. В командной оболочке bash для этого имеется специальная последовательность « 2>&1 ». Это означает «направить стандартный вывод ошибок туда же, куда и стандартный вывод»:
$ info cat > cat.info 2>&1 $ head -3 cat.info info: Запись ноды (coreutils.info.bz2)cat invocation... info: Завершено. File: coreutils.info, Node: cat invocation, Next: tac invocation, Up: Output of entire files $
Пример 7 . Объединение стандартного вывода и стандартного вывода ошибок
В этом примере важен порядок перенаправлений: в командной строке Мефодий сначала указал, куда перенаправить стандартный вывод (« > cat.info ») и только потом велел направить туда же стандартный вывод ошибок. Сделай он наоборот (« 2>&1 > cat.info »), результат получился бы неожиданный: в файл попал бы только стандартный вывод, а диагностические сообщения появились бы на терминале. Однако логика здесь железная: на момент выполнения операции « 2>&1 » стандартный вывод был связан с терминалом, значит, после её выполнения стандартный вывод ошибок тоже будет связан с терминалом. А последующее перенаправление стандартного вывода в файл, конечно, никак не отразится на стандартном выводе ошибок. Номер в конструкции « &номер » - это номер открытого дескриптора. Если бы упомянутая выше утилита, записывающая в четвёртый дескриптор, была написана на shell, в ней бы использовались перенаправления вида « >&4 ». Чтобы не набирать громоздкую конструкцию « > файл 2>&1 » в bash используются сокращения: « &> файл » или, что то же самое, « >& файл ».
Перенаправление в никуда
Иногда заведомо известно, что какие-то данные, выведенные программой, не понадобятся. Например, предупреждения со стандартного вывода ошибок. В этом случае можно перенаправить стандартный вывод ошибок в файл-дырку , специально предназначенный для уничтожения данных - /dev/null . Всё, что записывается в этот файл, просто будет выброшено и нигде не сохранится .
$ info cat > cat.info 2> /dev/null $
Пример 8 . Перенаправление в /dev/null
Точно таким же образом можно избавиться и от стандартного вывода, отправив его в /dev/null .
- Перевод
Если вы уже освоились с основами терминала, возможно, вы уже готовы к тому, чтобы комбинировать изученные команды. Иногда выполнения команд оболочки по одной вполне достаточно для решения некоей задачи, но в некоторых случаях вводить команду за командой слишком утомительно и нерационально. В подобной ситуации нам пригодятся некоторые особые символы, вроде угловых скобок.
Для оболочки, интерпретатора команд Linux, эти дополнительные символы - не пустая трата места на экране. Они - мощные команды, которые могут связывать воедино различные фрагменты информации, разделять то, что было до этого цельным, и делать ещё много всего. Одна из самых простых, и, в то же время, мощных и широко используемых возможностей оболочки - это перенаправление стандартных потоков ввода/вывода.
Три стандартных потока ввода/вывода
Для того, чтобы понять то, о чём мы будем тут говорить, важно знать, откуда берутся данные, которые можно перенаправлять, и куда они идут. В Linux существует три стандартных потока ввода/вывода данных.Первый - это стандартный поток ввода (standard input). В системе это - поток №0 (так как в компьютерах счёт обычно начинается с нуля). Номера потоков ещё называют дескрипторами. Этот поток представляет собой некую информацию, передаваемую в терминал, в частности - инструкции, переданные в оболочку для выполнения. Обычно данные в этот поток попадают в ходе ввода их пользователем с клавиатуры.
Второй поток - это стандартный поток вывода (standard output), ему присвоен номер 1. Это поток данных, которые оболочка выводит после выполнения каких-то действий. Обычно эти данные попадают в то же окно терминала, где была введена команда, вызвавшая их появление.
И, наконец, третий поток - это стандартный поток ошибок (standard error), он имеет дескриптор 2. Этот поток похож на стандартный поток вывода, так как обычно то, что в него попадает, оказывается на экране терминала. Однако, он, по своей сути, отличается от стандартного вывода, как результат, этими потоками, при желании, можно управлять раздельно. Это полезно, например, в следующей ситуации. Есть команда, которая обрабатывает большой объём данных, выполняя сложную и подверженную ошибкам операцию. Нужно, чтобы полезные данные, которые генерирует эта команда, не смешивались с сообщениями об ошибках. Реализуется это благодаря раздельному перенаправлению потоков вывода и ошибок.
Как вы, вероятно, уже догадались, перенаправление ввода/вывода означает работу с вышеописанными потоками и перенаправление данных туда, куда нужно программисту. Делается это с использованием символов > и < в различных комбинациях, применение которых зависит от того, куда, в итоге, должны попасть перенаправляемые данные.
Перенаправление стандартного потока вывода
Предположим, вы хотите создать файл, в который будут записаны текущие дата и время. Дело упрощает то, что имеется команда, удачно названная date , которая возвращает то, что нам нужно. Обычно команды выводят данные в стандартный поток вывода. Для того, чтобы эти данные оказались в файле, нужно добавить символ > после команды, перед именем целевого файла. До и после > надо поставить пробел.При использовании перенаправления любой файл, указанный после > будет перезаписан. Если в файле нет ничего ценного и его содержимое можно потерять, в нашей конструкции допустимо использовать уже существующий файл. Обычно же лучше использовать в подобном случае имя файла, которого пока не существует. Этот файл будет создан после выполнения команды. Назовём его date.txt . Расширение файла после точки обычно особой роли не играет, но расширения помогают поддерживать порядок. Итак, вот наша команда:
$ date > date.txt
Нельзя сказать, что сама по себе эта команда невероятно полезна, однако, основываясь на ней, мы уже можем сделать что-то более интересное. Скажем, вы хотите узнать, как меняются маршруты вашего трафика, идущего через интернет к некоей конечной точке, ежедневно записывая соответствующие данные. В решении этой задачи поможет команда traceroute , которая сообщает подробности о маршруте трафика между нашим компьютером и конечной точкой, задаваемой при вызове команды в виде URL. Данные включают в себя сведения обо всех маршрутизаторах, через которые проходит трафик.
Так как файл с датой у нас уже есть, будет вполне оправдано просто присоединить к этому файлу данные, полученные от traceroute . Для того, чтобы это сделать, надо использовать два символа > , поставленные один за другим. В результате новая команда, перенаправляющая вывод в файл, но не перезаписывающая его, а добавляющая новые данные после старых, будет выглядеть так:
$ traceroute google.com >> date.txt
Теперь нам осталось лишь изменить имя файла на что-нибудь более осмысленное, используя команду mv , которой, в качестве первого аргумента, передаётся исходное имя файла, а в качестве второго - новое:
$ mv date.txt trace1.txt
Перенаправление стандартного потока ввода
Используя знак < вместо > мы можем перенаправить стандартный ввод, заменив его содержимым файла.Предположим, имеется два файла: list1.txt и list2.txt , каждый из которых содержит неотсортированный список строк. В каждом из списков имеются уникальные для него элементы, но некоторые из элементов список совпадают. Мы можем найти строки, которые имеются и в первом, и во втором списках, применив команду comm , но прежде чем её использовать, списки надо отсортировать.
Существует команда sort , которая возвращает отсортированный список в терминал, не сохраняя отсортированные данные в файл, из которого они были взяты. Можно отправить отсортированную версию каждого списка в новый файл, используя команду > , а затем воспользоваться командой comm . Однако, такой подход потребует как минимум двух команд, хотя то же самое можно сделать в одной строке, не создавая при этом ненужных файлов.
Итак, мы можем воспользоваться командой < для перенаправления отсортированной версии каждого файла команде comm . Вот что у нас получилось:
$ comm <(sort list1.txt) <(sort list2.txt)
Круглые скобки тут имеют тот же смысл, что и в математике. Оболочка сначала обрабатывает команды в скобках, а затем всё остальное. В нашем примере сначала производится сортировка строк из файлов, а потом то, что получилось, передаётся команде comm , которая затем выводит результат сравнения списков.
Перенаправление стандартного потока ошибок
И, наконец, поговорим о перенаправлении стандартного потока ошибок. Это может понадобиться, например, для создания лог-файлов с ошибками или объединения в одном файле сообщений об ошибках и возвращённых некоей командой данных.Например, что если надо провести поиск во всей системе сведений о беспроводных интерфейсах, которые доступны пользователям, у которых нет прав суперпользователя? Для того, чтобы это сделать, можно воспользоваться мощной командой find .
Обычно, когда обычный пользователь запускает команду find по всей системе, она выводит в терминал и полезные данные и ошибки. При этом, последних обычно больше, чем первых, что усложняет нахождение в выводе команды того, что нужно. Решить эту проблему довольно просто: достаточно перенаправить стандартный поток ошибок в файл, используя команду 2> (напомним, 2 - это дескриптор стандартного потока ошибок). В результате на экран попадёт только то, что команда отправляет в стандартный вывод:
$ find / -name wireless 2> denied.txt
Как быть, если нужно сохранить результаты работы команды в отдельный файл, не смешивая эти данные со сведениями об ошибках? Так как потоки можно перенаправлять независимо друг от друга, в конец нашей конструкции можно добавить команду перенаправления стандартного потока вывода в файл:
$ find / -name wireless 2> denied.txt > found.txt
Обратите внимание на то, что первая угловая скобка идёт с номером - 2> , а вторая без него. Это так из-за того, что стандартный вывод имеет дескриптор 1, и команда > подразумевает перенаправление стандартного вывода, если номер дескриптора не указан.
И, наконец, если нужно, чтобы всё, что выведет команда, попало в один файл, можно перенаправить оба потока в одно и то же место, воспользовавшись командой &> :
$ find / -name wireless &> results.txt
Итоги
Тут мы разобрали лишь основы механизма перенаправления потоков в интерпретаторе командной строки Linux, однако даже то немногое, что вы сегодня узнали, даёт вам практически неограниченные возможности. И, кстати, как и всё остальное, что касается работы в терминале, освоение перенаправления потоков требует практики. Поэтому рекомендуем вам приступить к собственным экспериментам с > и < .Уважаемые читатели! Знаете ли вы интересные примеры использования перенаправления потоков в Linux, которые помогут новичкам лучше освоиться с этим приёмом работы в терминале?
Если вывод в (графическую) консоль не очень объёмный, можно просто выдельть мышкой кусок и вставить его в сообщение щелчком средней кнопки. В противном случае можно использовать перенаправление вывода в файл через "воронку", например так:
Some_command parameters > logfile.txt
Чтобы видеть результат выполнения на экране, и одновременно писать в файл, можно воспользоваться командой tee :
Some_command parameters | tee -a logfile.txt
Команда setterm -dump создает "слепок" буфера текущей виртуальной консоли в виде простого текстового файла с именем по умолчанию - screen.dump. В качестве ее аргумента можно использовать номер консоли, для которой требуется сделать дамп. А добавление опции -file имя_файла перенаправит этот дамп в файл с указанным именем. Опция же -append присоединит новый дамп к уже существующему файлу - "умолчальному" screen.dump или поименованному опцией -file .
Т.е. после использования команды, например
Setterm -dump -file /root/screenlog
соответственно в файле /root/screenlog будет содержимое одной страницы консоли.
Нашёл еще одно решение для копирования/вставки текста в текстовой консоли без мыши. Также можно копировать текст из буфера прокрутки (т.е. всё что на экране и выше за экраном). Чтобы лучше разобраться, читайте о консольном менеджере окон screen . Также может пригодиться увеличить размер буфера прокрутки.
1) Запускаем screen
2) Нажимаем Enter. Всё. Мы находимся в нулевом окне консоли.
3) Выполняем нужные команды, вывод которых необходимо скопировать.
4) Ctrl+A, Ctrl+[ - мы в режиме копирования. Ставим курсор на начало выделения, жмём пробел, потом ставим курсор на конец выделения, жмём пробел. Текст скопирован в буфер.
5) Ctrl+A, с - мы создали новое 1-е окно.
6) Ctrl+A, 1 - мы перешли на 1-е окно.
7) Открываем любой (?) текстовый редактор (я пробовал в mc), и жмём Ctrl+A, Ctrl+] - текст вставлен. Сохраняем.
8) Ctrl+A, Ctrl+0 - вернуться обратно в нулевое окно.
Как увеличить буфер обратной прокрутки?
Первым решением будет увеличить дефолтный (умолчальный) размер буфера в исходниках ядра и перекомпилировать его. Позвольте предположить, что вы столь же не склонны заниматься этим, как и я, и поискать средство более гибкое.
И такое средство есть, а называется оно framebuffer console , для краткости fbcon . Это устройство имеет файл документации fbcon.txt ; если вы устанавливали документацию к ядру, то он у вас есть. Выискивайте его где-то в районе /usr/share ветви (я не могу указать точный путь из-за разницы в дистрибутивах).
На этом месте прошу прощения: мы должны сделать небольшое отступление и немного поговорить о видеобуфере (framebuffer ).
Видеобуфер - это буфер между дисплеем и видеоадаптером. Его прелесть в том, что им можно манипулировать: он позволяет трюки, которые не прошли бы, будь адаптер связан напрямую с дисплеем.
Один из таких трюков связан с буфером прокрутки; оказывается, вы можете "попросить" видеобуфер выделить больше памяти буферу прокрутки. Достигается это через загрузочные параметры ядра. Сначала вы требуете framebuffer (видеобуфер); Затем запрашиваете больший буфер прокрутки.
Нижеследующий пример касается GRUB , но может быть легко адаптирован к LILO . В файле настройки GRUB - menu.lst - найдите соответствующую ядру строчку, и затем: Удалите опцию vga=xxx , если таковая присутствует. Добавьте опцию video=vesabf или то, что соответствует вашему "железу". Добавьте опцию fbcon=scrollback:128 . После этой процедуры, строка параметров ядра должна выглядеть приблизительно так:
Kernel /vmlinuz root=/dev/sdb5 video=radeonfb fbcon=scrollback:128
Спрашивается, зачем удалять опцию vga=xxx ? Из-за возможных конфликтов с видео-опцией. На своем ATI адаптере, я не могу изменить буфер прокрутки, если vga=xxx присутствует в списке. Возможно в вашем случае это не так. Если вышеперечисленные опции работают - хорошо; но что, если вы хотите увеличить число строк, или установить более мелкий шрифт на экране? Вы всегда делали это при помощи опции vga=xxx - а она-то и исчезла. Не переживайте - то же самое может быть достигнуто изменением параметров fbcon, как описано в файле fbcon.txt (но не описано в данной статье).
С опцией fbcon=scrollback:128 у меня буфер прокрутки увеличился до 17 экранов (35 раз Shift+PgUp по полэкрана). Кстати, 128 - это килобайт. Автор статьи утверждает, что больше установить нельзя. Я и не пробовал.
Можно заюзать script .
Script filename.log
когда все нужные команды выполнены -
Все записано в filename.log
В FreeBSD есть замечательная утилита watch, которая позволяет мониторить терминалы, но как оказалось, в Linux она выполняет совсем иные функции =\ Стоит погуглить на эту тему, чего-нть да найдется...
Доброго времени, читатели моего !
В данной статье хочу систематизировать свои знания по основным принципам работы программных потоков и каналов
в интерпретаторе и в общем в ОС Linux, а так же о возможностях перенаправления
данных потоков
.
В самом начале хочу отметить, что интерпретатор работает с тремя стандартными потоками:
- stdout это стандартный поток вывода , который обеспечивает вывод команды. Дескриптор потока равен 1.
- stderr это стандартный поток ошибок , который выводит ошибки команд. Его дескриптор равен 2.
- stdin это стандартный поток ввода , который обеспечивает ввод командам. Его дескриптор равен 0.
Теперь простыми словами опишем, что эти три пункта обозначают:
stdout - стандартный поток вывода. Это, говоря простым языком, та информация, которую мы видим в интерпретаторе при выполнении команд. То есть все сообщения (без сообщений об ошибках), которые выполняемая в интерпретаторе команда сообщает и выводит на терминал (читай - экран). (вывод на экран задан по умолчанию, но можно указать и вывод, например в файл или перенаправление в другую команду, как это делается, расскажу ниже)
stderr - поток ошибок. Это ошибки при выполнении команд в bash, которые по умолчанию выводятся на stdout, то есть на терминал (опять же, если не указан вывод в другое место)
stdin - поток ввода. Это, говоря простым языком - то, что мы вводим с клавиатуры в интерпретатор для выполнения команды.
Очень хорошо данные потоки изображены на рисунке, взятом с http://rus-linux.net/:
На данном изображении: Stdin
, показан зеленым, имеет дескриптор 0
Stdout
, показан красным, имеет дескриптор 1
Stderr
, показан синим, имеет дескриптор 2
Далее расскажу, как данные потоки можно перенаправить в/из файл. То есть при выполнении команды, чтобы сообщения или ошибки выводились не на экран, а записывались в файл. Для чего это нужно? Ну например вы выполняете какую-то команду, у которой вывод не помещается в окно терминала. Вы указываете сохранять стандартный вывод в один файл, а стандартный поток ошибок в другой. Тем самым, все ошибки и если нужно стандартный вывод, можно будет посмотреть подробно, открыв сохраненные файлы.
Итак, перенаправление потоков выполняется следующим образом:
$ command n>file
В данной строке показано: выполнение команды command и перенаправление потока (где n = дескриптору потока) в файл file. При выполнении данного перенаправления, если конечный файл существует, он будет перезаписан . При этом, если n не указан, то предполагается стандартный вывод.
$ command n>>file
Данная команда имеет аналогичный синтаксис, но тут указан символ ">>". При данном перенаправлении, если конечный файл существует, то вывод команды будет добавлен к имеющимся данным.
$ command < file
в данном примере команда command
выполняется и использует в качестве источника ввода, файл file,
вместо ввода с клавиатуры
Иногда возникает необходимость объединить стандартный поток ошибок со стандартным потоком вывода, чтобы можно было обрабатывать ошибки и обычные результаты работы программы вместе. для этих целей используется комбинация с символом: &. Пример выполнения данного действия:
Find / -name .name_file > /path/to/file 2>&1
При выполнении данной команды, происходит поиск файла от корня файловой системы с именем .name_file и перенаправление результатов поиска (stdout и stderr) в файл /path/to/file . Конструкция > /path/to/file 2>&1 перенаправляет стандартный вывод в /path/to/file и вывод ошибок в стандартный вывод. При этом: написание 2>&1 перед > не будет работать, так как когда интерпретатор прочитает 2>&1 , он еще не знает куда перенаправлен стандартный поток вывода, поэтому потоки ошибок и вывода не будут объединены.
$ command > file 2>&1
аналогична написанию:
$ command &> file
$ command 2>&file
Если необходимо проигнорировать вывод, его можно направить в устройство /dev/null, это своего рода "черная дыра", принимающая любое количество информации и превращающая ее в ничто.
Думаю приведенной информации о перенаправлении потоко будет достаточно для понимания сути, теперь расскажу о конвеерной передаче .
Конвеер в Linux - это возможность нескольких программ работать совместно, когда выход одной программы непосредственно передается на вход другой без использования промежуточных временных файлов. Синтаксис использования конвеера следующий:
$ command1 | command2
В данном примере выполняется команда command1 , ее поток вывода используется, как поток ввода при выполнении command2 .
На сегодня все. Буду рад комментариям и дополнениям. Спасибо.
С Уважением, Mc.Sim!