Stdin linux что это

Обновлено: 25.06.2024

В прошлый раз, в третьей части этой серии материалов по bash-скриптам, мы говорили о параметрах командной строки и ключах. Наша сегодняшняя тема — ввод, вывод, и всё, что с этим связано.

image



Вы уже знакомы с двумя методами работы с тем, что выводят сценарии командной строки:

  • Отображение выводимых данных на экране.
  • Перенаправление вывода в файл.

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

Всё в Linux — это файлы, в том числе — ввод и вывод. Операционная система идентифицирует файлы с использованием дескрипторов.

Каждому процессу позволено иметь до девяти открытых дескрипторов файлов. Оболочка bash резервирует первые три дескриптора с идентификаторами 0, 1 и 2. Вот что они означают.

  • 0 , STDIN — стандартный поток ввода.
  • 1 , STDOUT — стандартный поток вывода.
  • 2 , STDERR — стандартный поток ошибок.

STDIN

STDIN — это стандартный поток ввода оболочки. Для терминала стандартный ввод — это клавиатура. Когда в сценариях используют символ перенаправления ввода — < , Linux заменяет дескриптор файла стандартного ввода на тот, который указан в команде. Система читает файл и обрабатывает данные так, будто они введены с клавиатуры.

Многие команды bash принимают ввод из STDIN , если в командной строке не указан файл, из которого надо брать данные. Например, это справедливо для команды cat .

Когда вы вводите команду cat в командной строке, не задавая параметров, она принимает ввод из STDIN . После того, как вы вводите очередную строку, cat просто выводит её на экран.

STDOUT

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


То, что выведет pwd , будет добавлено к файлу myfile , при этом уже имеющиеся в нём данные никуда не денутся.

Перенаправление вывода команды в файл

Попытка обращения к несуществующему файлу

STDERR

▍Перенаправление потока ошибок

▍Перенаправление потоков ошибок и вывода

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

Перенаправление STDERR и STDOUT в один и тот же файл

После выполнения команды то, что предназначено для STDERR и STDOUT , оказывается в файле content .

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

Существует два метода перенаправления вывода в сценариях командной строки:

  • Временное перенаправление, или перенаправление вывода одной строки.
  • Постоянное перенаправление, или перенаправление всего вывода в скрипте либо в какой-то его части.

▍Временное перенаправление вывода


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

Временное перенаправление

Запустим скрипт так, чтобы вывод STDERR попадал в файл.

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

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

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

Если просмотреть файл, указанный в команде перенаправления вывода, окажется, что всё, что выводилось командами echo , попало в этот файл.

Команду exec можно использовать не только в начале скрипта, но и в других местах:


Вот что получится после запуска скрипта и просмотра файлов, в которые мы перенаправляли вывод.

Перенаправление вывода в разные файлы

Сначала команда exec задаёт перенаправление вывода из STDERR в файл myerror . Затем вывод нескольких команд echo отправляется в STDOUT и выводится на экран. После этого команда exec задаёт отправку того, что попадает в STDOUT , в файл myfile , и, наконец, мы пользуемся командой перенаправления в STDERR в команде echo , что приводит к записи соответствующей строки в файл myerror.

Освоив это, вы сможете перенаправлять вывод туда, куда нужно. Теперь поговорим о перенаправлении ввода.

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

Для перенаправления ввода можно воспользоваться той же методикой, которую мы применяли для перенаправления вывода. Например, команда exec позволяет сделать источником данных для STDIN какой-нибудь файл:


Эта команда указывает оболочке на то, что источником вводимых данных должен стать файл myfile , а не обычный STDIN . Посмотрим на перенаправление ввода в действии:


Вот что появится на экране после запуска скрипта.

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

Некоторые администраторы Linux используют этот подход для чтения и последующей обработки лог-файлов.

Создание собственного перенаправления вывода

Перенаправляя ввод и вывод в сценариях, вы не ограничены тремя стандартными дескрипторами файлов. Как уже говорилось, можно иметь до девяти открытых дескрипторов. Остальные шесть, с номерами от 3 до 8, можно использовать для перенаправления ввода или вывода. Любой из них можно назначить файлу и использовать в коде скрипта.

Назначить дескриптор для вывода данных можно, используя команду exec :


После запуска скрипта часть вывода попадёт на экран, часть — в файл с дескриптором 3 .

Перенаправление вывода, используя собственный дескриптор

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

После окончания чтения файла можно восстановить STDIN и пользоваться им как обычно:

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

В этом примере дескриптор файла 6 использовался для хранения ссылки на STDIN . Затем было сделано перенаправление ввода, источником данных для STDIN стал файл. После этого входные данные для команды read поступали из перенаправленного STDIN , то есть из файла.

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

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

Попытка обращения к закрытому дескриптору файла

Всё дело в том, что мы попытались обратиться к несуществующему дескриптору.

Будьте внимательны, закрывая дескрипторы файлов в сценариях. Если вы отправляли данные в файл, потом закрыли дескриптор, потом — открыли снова, оболочка заменит существующий файл новым. То есть всё то, что было записано в этот файл ранее, будет утеряно.

Получение сведений об открытых дескрипторах

Для того, чтобы получить список всех открытых в Linux дескрипторов, можно воспользоваться командой lsof . Во многих дистрибутивах, вроде Fedora, утилита lsof находится в /usr/sbin . Эта команда весьма полезна, так как она выводит сведения о каждом дескрипторе, открытом в системе. Сюда входит и то, что открыли процессы, выполняемые в фоне, и то, что открыто пользователями, вошедшими в систему.

У этой команды есть множество ключей, рассмотрим самые важные.

  • -p Позволяет указать ID процесса.
  • -d Позволяет указать номер дескриптора, о котором надо получить сведения.

Ключ -a используется для выполнения операции логического И над результатами, возвращёнными благодаря использованию двух других ключей:

Вывод сведений об открытых дескрипторах

Тип файлов, связанных с STDIN , STDOUT и STDERR — CHR (character mode, символьный режим). Так как все они указывают на терминал, имя файла соответствует имени устройства, назначенного терминалу. Все три стандартных файла доступны и для чтения, и для записи.

Посмотрим на вызов команды lsof из скрипта, в котором открыты, в дополнение к стандартным, другие дескрипторы:


Вот что получится, если этот скрипт запустить.

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

Скрипт открыл два дескриптора для вывода ( 3 и 6 ) и один — для ввода ( 7 ). Тут же показаны и пути к файлам, использованных для настройки дескрипторов.

Подавление вывода


Тот же подход используется, если, например, надо очистить файл, не удаляя его:

Итоги

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

В следующий раз поговорим о сигналах Linux, о том, как обрабатывать их в сценариях, о запуске заданий по расписанию и о фоновых задачах.

BASH

Статья посвящена работой с потоками данных в bash. Я постарался написать ее наиболее доступным и простым языком, чтобы было понятно даже новичкам в Linux.


В одной из моих статей мы рассматривали запись звука в файл с помощью команды:

Эта команда читает файл (устройство) /dev/audio с помощью команды cat и перенаправляет информацию из него в файл /tmp/my.sound (с помощью оператора >).

У каждой программы существует 3 системных потока: stdout, stderr, stdin.

stdout

Стандартный поток вывода данных для программ. Например, когда мы пишем команду ls, то список папок и файлов она выводит именно в этот поток, который отображается у нас в консоли:

stderr

Поток вывода ошибок. Если программа не смогла сделать все как надо — она пишет именно в этот поток. Например, когда rm пытается удалить несуществующий файл:

$ rm example.txt
rm: example.txt: No such file or directory

stdin

Поток ввода данных. А вот это довольно интересный и удобный поток. Например, его использует вэб-сервер, когда просит интерпретаторы выполнить скрипты через CGI. Мы тоже можем попробовать:

В этом примере мы встретили оператор перенаправления потока вывода. Мы остановимся на нем позже.

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

В этом примере мы направили stdout команды ls в файл 1.txt. Читаем его:

Да, все успешно записалось.

Мы можем направлять одни потоки в направлении других:

В этом примере мы направили поток stdout в файл 1.txt, а затем направили stderr туда же, куда направлен stdout с помощью оператора & перед номером потока.

Теперь давайте поиграем с потоком stdin. Например, я хочу найти все папки ".svn" в некотором проекте и удалить:

Команда find с параметром. выводит в stdout все вложенные папки и файлы, которые находит в данной папке и во всех вложенных.

Теперь нам надо выбрать только папки с именем ".svn":

Оператор | перенаправляет stdout одного приложения в stdin следующего. То есть все строки найденные с помощью find пошли в команду grep, которая выбирает строки по определенным условиям и выводит их. Здесь условие — это регулярное выражение, которое говорит о том, что строка должна заканчиваться на "/.svn".

Нужные папки мы выбрали, осталось их удалить.

И снова новый оператор: `. Он забирает stdout из команды, которую он окружает и вставляет в данное место как строку.

Получается, что мы запросили все файлы, выбрали из них папки с именем ".svn" и отдали результат как аргументы команде rm. В этом случае у нас будут проблемы если имена файлов и папок содержат пробелы. Исправляем ситуацию:

Теперь мы отдаем нужные файлы команде xargs, которая вызывает rm -Rf и в качестве параметров использует свой stdin построчно. Задача решена.

В системах Linux и Unix существуют стандартные входной (STDIN) и выходные (STDOUT, STDERR) потоки (каналы). Далее рассмотрим подробнее каждый из них.

В рамках терминала канал STDIN считывает входные данные, а каналы STDOUT и STDERR выводят выходные данные на экран.

Управление потоками

Для перенаправления каналов в терминале, применяют определенные символы. Рассмотрим каждый из них на примере команды поиска системных файлов, которые содержат слово - core. Все найденные файлы будут формироваться в поток STDOUT. Те найденные файлы, к которым у обычного пользователя нет доступа будут попадать в STDERR.

find / -name core > /tmp/testfile

В файл /tmp/testfile попадет список путей ко всем найденным файлам, а список ошибок отобразится в терминале.

Запись в файл

Запись STDOUT в файл

Символ > - затирает все его содержимое и вставляет значение из потока, поэтому будьте осторожны при правке системных файлов используя данный символ. Если Вам нужно добавить данные в конец файла - используйте два последовательных символа - >> .

find / -name core >> /tmp/testfile

В конец файла /tmp/testfile попадет список путей ко всем найденным файлам, а список ошибок отобразится в терминале.

find / -name core >& /tmp/testfile

С помощью составного символа - >& мы объединяем стандартный выходной поток с выходным потоком ошибок. В файл /tmp/testfile попадет список путей ко всем найденным файлам и список ошибок.

find / -name core 2> /tmp/testfile

В файл /tmp/testfile попадет список ошибок, а список найденных файлов, будет выведен в терминале.

Вывод STDERR

Вывод STDERR

Вывод потоков можно комбинировать и распределять по разным местам. Например, выведем список найденных файлов в /tmp/testfile , а список ошибок отбросим, перенаправив их в /dev/null .

find / -name core > /tmp/testfile 2> /dev/null

Перенаправление потоков

Перенаправление потоков

Для примера, выведем в консоли отдельные процессы системы с именем - chrome .

ps | grep chrome

Здесь результат выполнения команды ps передается в роли входных данных для команды grep , в которых она ищет совпадения с именем chrome .

Заключение

В этой небольшой статье мы рассмотрели все стандартные входные и выходные и потоки, которые, в свою очередь, очень часто применяются системными администраторами на практике.


Потоки объединяются в две точки

У потоков данных, как и у водных потоков, есть два конца. У них есть источник и отток. Какую бы команду Linux вы ни использовали, она обеспечивает один конец каждого потока. Другой конец определяется оболочкой, запустившей команду. Этот конец будет подключен к окну терминала, подключен к каналу или перенаправлен к файлу или другой команде в соответствии с командной строкой, запустившей команду.

Стандартные потоки Linux

Потоки обрабатываются как файлы

Каждому файлу, связанному с процессом, присваивается уникальный номер для его идентификации. Это известно как файловый дескриптор. Всякий раз, когда требуется выполнить действие с файлом, дескриптор файла используется для идентификации файла.

Эти значения всегда используются для stdin, stdout и stderr:

0: стандартный ввод
1: стандартный вывод
2: stderr

Реакция на каналы и перенаправления

Аналогичным образом, говоря о stdin, stdout и stderr, удобно использовать общепринятую аксиому о том, что процесс не знает и не заботится о том, где завершаются его три стандартных потока. Должен ли процесс заботиться о том, идет ли его вывод на терминал или перенаправляется в файл? Может ли он даже сказать, идет ли его ввод с клавиатуры или передается в него из другого процесса?

Проверь это - Как сделать Linux похожим на Windows XP

Мы можем очень легко увидеть это изменение в поведении. Попробуйте эти две команды:

ls вывод в окне терминала

Команда ls ведет себя иначе, если ее вывод (stdout) передается другой команде. Это ls, который переключается на вывод в один столбец, это не преобразование, выполняемое cat. И ls делает то же самое, если его вывод перенаправляется:


Перенаправление stdout и stderr

Введите следующий текст в редактор и сохраните его в файл с именем error.sh.

Сделайте скрипт исполняемым с помощью этой команды:

Запустите сценарий с помощью этой команды:

Мы видим, что оба потока вывода, stdout и stderr, были отображены в окнах терминала.

Вывод из стандартного ввода был перенаправлен в файл, как и ожидалось.

Давайте попробуем снова провести наш тест, и на этот раз мы будем использовать 2>:

Проверь это - Как зашифровать и расшифровать файлы с помощью GPG в Linux

Перенаправление как stdout, так и stderr

Да мы можем. Эта команда направит stdout в файл с именем capture.txt и stderr в файл с именем error.txt.

Проверим содержимое каждого файла:

Перенаправление stdout и stderr в один файл

Мы можем добиться этого с помощью следующей команды:

Давайте разберемся с этим.

Давайте проверим файл capture.txt и посмотрим, что в нем.

И потоки stdout, и потоки stderr были перенаправлены в один файл назначения.

Чтобы вывод потока перенаправлялся и незаметно отбрасывался, направьте вывод в / dev / null.

Обнаружение перенаправления в сценарии

Мы обсудили, как команда может определить, перенаправляется ли какой-либо из потоков, и может соответствующим образом изменить свое поведение. Можем ли мы сделать это в наших собственных сценариях? Да мы можем. И это очень простой метод для понимания и применения.

Введите следующий текст в редактор и сохраните его как input.sh.

Используйте следующую команду, чтобы сделать его исполняемым:

Проверь это - Как установить почтовый клиент Hiri в Linux

Если stdin подключен к окну терминала, тест подтвердится. Если stdin подключен к файлу или каналу, тест завершится неудачно.

Мы можем использовать любой удобный текстовый файл для генерации входных данных в скрипт. Здесь мы используем файл dummy.txt.

Сценарий распознает, что его ввод передается по конвейеру. Или, точнее, он еще раз распознает, что поток stdin не подключен к окну терминала.

Запустим скрипт без каналов и перенаправлений.

Поток stdin подключен к окну терминала, и сценарий сообщает об этом соответственно.

Чтобы проверить то же самое с выходным потоком, нам нужен новый скрипт. Введите в редактор следующее и сохраните как output.sh.

Используйте следующую команду, чтобы сделать его исполняемым:

Единственное существенное изменение в этом скрипте - это тест в квадратных скобках. Мы используем цифру 1 для обозначения файлового дескриптора для stdout.

Давай попробуем. Мы пропустим вывод через cat.

Сценарий распознает, что его вывод не идет напрямую в окно терминала.

Мы также можем протестировать скрипт, перенаправив вывод в файл.

В окне терминала нет вывода, мы молча возвращаемся в командную строку. Как и следовало ожидать.

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

Опять же, простой тест в нашем скрипте обнаруживает, что поток stdout не отправляется непосредственно в окно терминала.

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

И это именно то, что мы видим.

Потоки сознания

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

Читайте также: