Тарифы Услуги Сим-карты

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

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

  • выводить сообщения программ не на экран (стандартный выходной поток), а в файл или на принтер (перенаправление вывода);
  • читать входные данные не с клавиатуры (стандартный входной поток), а из заранее подготовленного файла (перенаправление ввода);
  • передавать сообщения, выводимые одной программой, в качестве входных данных для другой программы (конвейеризация или композиция команд).

Из командной строки эти возможности реализуются следующим образом. Для того, чтобы перенаправить текстовые сообщения, выводимые какой-либо командой из командной строки, в текстовый файл, нужно использовать конструкцию команда > имя_файла. Если при этом заданный для вывода файл уже существовал, то он перезаписывается (старое содержимое теряется), если не существовал создается. Можно также не создавать файл заново, а дописывать информацию, выводимую командой, в конец существующего файла. Для этого команда перенаправления вывода должна быть задана так: команда >> имя_файла . С помощью символа < можно прочитать входные данные для заданной команды не с клавиатуры, а из определенного (заранее подготовленного) файла: команда < имя_файла

Примеры перенаправления ввода/вывода в командной строке

Приведем несколько примеров перенаправления ввода/вывода.

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 обрабатывается ввод и вывод, а значит - научиться отправлять результаты работы сценариев туда, куда нужно. Начнём с разговора о стандартных дескрипторах файлов.

Стандартные дескрипторы файлов

Всё в 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 Позволяет указать номер дескриптора, о котором надо получить сведения.
Для того, чтобы узнать PID текущего процесса, можно использовать специальную переменную окружения $$ , в которую оболочка записывает текущий PID .

Ключ -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, а так же о возможностях перенаправления данных потоков .
В самом начале хочу отметить, что интерпретатор работает с тремя стандартными потоками:

  1. stdout это стандартный поток вывода , который обеспечивает вывод команды. Дескриптор потока равен 1.
  2. stderr это стандартный поток ошибок , который выводит ошибки команд. Его дескриптор равен 2.
  3. 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!