Перенаправление в файл. Перенаправление стандартных потоков ввода вывода
С помощью переназначения устройств ввода/вывода одна программа может направить свой вывод на вход другой или перехватить вывод другой программы, используя его в качестве своих входных данных. Таким образом, имеется возможность передавать информацию от процесса к процессу при минимальных программных издержках. Практически это означает, что для программ, которые используют стандартные входные и выходные устройства, операционная система позволяет:
- выводить сообщения программ не на экран (стандартный выходной поток), а в файл или на принтер (перенаправление вывода);
- читать входные данные не с клавиатуры (стандартный входной поток), а из заранее подготовленного файла (перенаправление ввода);
- передавать сообщения, выводимые одной программой, в качестве входных данных для другой программы (конвейеризация или композиция команд).
Из командной строки эти возможности реализуются следующим образом. Для того, чтобы перенаправить текстовые сообщения, выводимые какой-либо командой из командной строки, в текстовый файл, нужно использовать конструкцию команда > имя_файла. Если при этом заданный для вывода файл уже существовал, то он перезаписывается (старое содержимое теряется), если не существовал создается. Можно также не создавать файл заново, а дописывать информацию, выводимую командой, в конец существующего файла. Для этого команда перенаправления вывода должна быть задана так: команда >> имя_файла . С помощью символа < можно прочитать входные данные для заданной команды не с клавиатуры, а из определенного (заранее подготовленного) файла: команда < имя_файла
Примеры перенаправления ввода/вывода в командной строке
Приведем несколько примеров перенаправления ввода/вывода.
1. Вывод результатов команды ping в файл ping ya.ru > ping.txt
2. Добавление текста справки для команды XCOPY в файл copy.txt: XCOPY /? >> copy.txt
В случае необходимости сообщения об ошибках (стандартный поток ошибок) можно перенаправить в текстовый файл с помощью конструкции команда 2> имя_файла В этом случае стандартный вывод будет производиться на экран. Также имеется возможность информационные сообщения и сообщения об ошибках выводить в один и тот же файл. Делается это следующим образом: команда > имя_файла 2>&1
Например, в приведенной ниже команде стандартный выходной поток и стандартный поток ошибок перенаправляются в файл copy.txt: XCOPY A:\1.txt C: > copy.txt 2>&1
Перенаправление обычно осуществляется вставкой специального символа "> " между командами. Обычно синтаксис выглядит так:
Команда1 > файл1
выполняет команду1, помещая стандартный вывод в файл1.
Команда1 < файл1
выполняет команду1, используя в качестве источника ввода файл1 (вместо клавиатуры).
Команда1 < файл1 > файл2
совмещает два предыдущих варианта. Выполняет команду1 вводя из файла1 и выводя в файл2
Конвейеры
Конвейеры - это возможность нескольких программ работать совместно, когда выход одной программы непосредственно идет на вход другой без использования промежуточных временных файлов. Синтаксис:
команда1 | команда2
Выполняет команду1 используя её поток вывода как поток ввода при выполнении команды2, что равносильно использованию двух перенаправлений и временного файла:
Команда1 > ВременныйФайл команда2 < ВременныйФайл rm ВременныйФайл
Хороший пример командных конвейеров - это объединение echo с другой командой для получения интерактивности в неинтерактивных средах, к примеру:
echo -e "ИмяПользователя\nПароль" | ftp localhost
Здесь запускается клиент, который подключается к localhost под именем ИмяПользователя, нажимает Enter и затем вводит пароль Пароль.
Перенаправление в/из стандартных файловых дескрипторов
В командной оболочке UNIX, произошедшей из Bourne shell, предыдущие два действия можно усовершенствовать, указав номер(файловый дескриптор) непосредственно перед символом перенаправления. Этот номер указывает какой именно поток используется для перенаправления. В UNIX существуют следующие стандартные потоки ввода/вывода:
К примеру:
Команда1 2 > файл1
В командных оболочках произошедших от C Shell по правилам синтаксиса для указания потока, в который осуществляется перенаправление нужно добавлять символ & после символа перенаправления.
Часто стандартный поток ошибок объединяют со стандартным потоком вывода, чтобы можно было обрабатывать ошибки и обычные результаты работы программы вместе. К примеру:
Find / -name .profile> results.txt 2>&1
попытается найти все файлы с именем.profile. Если выполнять эту команду без перенаправлений она будет направлять результаты поиска в , а сообщения об ошибках(к примеру о недостаточности прав доступа при попытке поиска в защищенных директориях) в . По умолчанию эти роли выполняет консоль. Если стандартный поток вывода направлен в файл результаты, то ошибки по-прежнему будут направляться в консоль. Чтобы и ошибки и результаты поиска направлялись в файл results.txt стандартные потоки ошибок и вывода были объединены используя 2>&1 .
Написание 2>&1 перед > не будет работать, так как когда интерпретатор прочитает 2>&1 , он ещё не знает куда перенаправлен стандартный поток вывода, поэтому потоки ошибок и вывода не будут объединены.
Если объединенный результат нужно направить на вход другой программы посредством конвейера, тогда последовательность 2>&1 должна стоять перед знаком конвейера. К примеру:
Find / -name .profile 2>&1 | less
Упрощенная форма записи команды:
Команда> файл 2>&1
выглядит так:
Команда &> файл
Команда>& файл
Цепочка конвейеров
Команды перенаправления и конвейеризации могут быть объединены в цепочки для получения более сложных команд, к примеру:
Ls | grep ".sh" | sort> shlist
Получает список содержимого текущей директории, который фильтруется, оставляя только строки содержащие ".sh", затем этот отфильтрованный список лексически сортируется и окончательный результат помещается в файл shlist. Конструкции подобного типа часто встречаются в скриптах командной оболочки UNIX.
Перенаправление в несколько выводов
Стандартная команда может перенаправить вывод команды в несколько мест одновременно. Пример:
Ls -lrt | tee файл1
направляет стандартный вывод команды ls -lrt (список файлов) как в консоль так и в файл1 .
Перенаправление с добавлением
В командной оболочке можно осуществить перенаправление в файл с добавлением в конец. При этом информация, хранящаяся в файле не будет удалена, а вся новая информация будет добавлена в конец этого файла. Синтаксис:
Команда1>> файл1
Встроенный документ
Некоторые оболочки, и даже прикладные ЯВУ (PHP], Perl) допускают синтаксис встроенных документов (см. Heredoc-синтаксис), позволяющий направлять входной поток из самого файла программы, например: cat« EOF Здесь помещается произвольный текст, в том числе включающий в себя специальные символы EOF
Завершающая сигнатура окончания встроенного документа EOF (можно использовать произвольное значение, но часто используется именно EOF - соответственно смыслу) должна начинаться с начала строки.
- Перевод
Если вы уже освоились с основами терминала, возможно, вы уже готовы к тому, чтобы комбинировать изученные команды. Иногда выполнения команд оболочки по одной вполне достаточно для решения некоей задачи, но в некоторых случаях вводить команду за командой слишком утомительно и нерационально. В подобной ситуации нам пригодятся некоторые особые символы, вроде угловых скобок.
Для оболочки, интерпретатора команд 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, которые помогут новичкам лучше освоиться с этим приёмом работы в терминале?
Вы уже знакомы с двумя методами работы с тем, что выводят сценарии командной строки:
- Отображение выводимых данных на экране.
- Перенаправление вывода в файл.
Стандартные дескрипторы файлов
Всё в 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, о том, как обрабатывать их в сценариях, о запуске заданий по расписанию и о фоновых задачах.
Уважаемые читатели! В этом материале даны основы работы с потоками ввода, вывода и ошибок. Уверены, среди вас есть профессионалы, которые могут рассказать обо всём этом то, что приходит лишь с опытом. Если так - передаём слово вам.
Доброго времени, читатели моего !
В данной статье хочу систематизировать свои знания по основным принципам работы программных потоков и каналов
в интерпретаторе и в общем в ОС 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!