мета-данные страницы
Это старая версия документа!
стандартные потоки ввода/вывода
Стандартные потоки ввода и вывода в UNIX/Linux наряду с файлами являются одним из наиболее распространённых средств для обмена информацией процессов с внешним миром, а перенаправления >, » и |, одной из самых популярных конструкций командного интерпретатора.
На этой странице рассматриваются как базовые вопросы использования потоков ввода/вывода, так и тонкости и хитрости, например, почему не работает echo text | read ver и многие другие.
Потоки и файлы
Процесс взаимодействия с пользователем выполняется в терминах записи и чтения в файл. То есть вывод на экран представляется как запись в файл, а ввод — как чтение файла. Файл, из которого осуществляется чтение, называется стандартным потоком ввода, а в который осуществляется запись — стандартным потоком вывода.
Стандартные потоки — воображаемые файлы, позволяющие осуществлять взаимодействие с пользователем как чтение и запись в файл. Кроме потоков ввода и вывода, существует еще и стандартный поток ошибок, на который выводятся все сообщения об ошибках и те информативные сообщения о ходе работы программы, которые не могут быть выведены в стандартный поток вывода.
Стандартные потоки привязаны к файловым дескрипторам с номерами 0, 1 и 2.
- Стандартный поток ввода (stdin) — 0;
- Стандартный поток вывода (stdout) — 1;
- Стандартный поток ошибок (stderr) — 2.
Вывод данных на экран и чтение их с клавиатуры происходит потому, что по умолчанию стандартные потоки ассоциированы с терминалом пользователя. Это не является обязательным — потоки можно подключать к чему угодно — к файлам, программам и даже устройствам. В командном интерпретаторе bash такая операция называется перенаправлением.
< файл- Использовать файл как источник данных для стандартного потока ввода.> файл- Направить стандартный поток вывода в файл. Если файл не существует, он будет создан; если существует — перезаписан сверху.2> файл- Направить стандартный поток ошибок в файл. Если файл не существует, он будет создан; если существует — перезаписан сверху.»файл- Направить стандартный поток вывода в файл. Если файл не существует, он будет создан; если существует — данные будут дописаны к нему в конец.2»файл- Направить стандартный поток ошибок в файл. Если файл не существует, он будет создан; если существует — данные будут дописаны к нему в конец.&>файлили>&файл- Направить стандартный поток вывода и стандартный поток ошибок в файл. Другая форма записи: >файл 2>&1.>&-- Закрыть поток вывода перед вызовом команды (спасибо [1]);2>&-- Закрыть поток ошибок перед вызовом команды (спасибо [2]);cat «EOFтекстEOF- Весь текст между блоками EOF (в общем случае вместо EOF можно использовать любое слово) будет выведен на экран. Важно: перед последним EOF не должно быть пробелов! (heredoc синтаксис).«<string- Аналогично, но только для одной строки (для bash версии 3 и выше)
Каналы
Стандартные потоки можно перенаправлять не только в файлы, но и на вход других программ. Если поток вывода одной программы соединить с потоком ввода другой программы, получится конструкция, называемая каналом, конвейером или пайпом (от англ. pipe, труба).
В bash канал выглядит как последовательность команд, отделенных друг от друга символом |:
команда1 | команда2 | команда3 ...
Стандартный поток вывода команды1 подключается к стандартному потоку ввода команды2, стандартный поток вывода команды2 в свою очередь подключается к потоку ввода команды3 и т.д.
В UNIX/Linux существует целый класс команд, предназначенных для преобразования потоков данных в каналах. Такие программы известны как фильтры. Программа-фильтр читает данные, поступающие со стандартного потока ввода (на вход), преобразовывает их требуемым образом и выводит на стандартный поток вывода (на выход). Существует множество хорошо известных фильтров, призванных решать определенные задачи, и являющихся незаменимым инструментом в руках пользователя ОС.
Программы, образующие канал, выполняются параллельно как независимые процессы.
Можно создавать ответвление в каналах. Команда tee позволяет сохранять данные, передающиеся в канале:
tee [опции] файл
Программа tee копирует данные, поступающие на стандартный поток ввода, в указанные в качестве аргументов команды файлы, и передает данные на стандартный поток вывода.
Рассмотренный ниже пример: сортируется файл unsortedlines и результат записывается в sortedlines.
cat unsortedlines | sort > sortedlines
Команда выполняет те же действия, но запись является более наглядной.
Вот пример посложнее. Вывести название и размер пользовательского каталога, занимающее наибольшее место на диске.
du -s /home/* | sort -nr | head -1
Программа du, при вызове ее с ключом -s, сообщает суммарный объем каждого каталога или файла, перечисленного в ее параметрах.
Ключ -n команды sort означает, что сортировка должна быть арифметической, т.е. строки должны рассматриваться как числа, а не как последовательности символов (Например, 12>5 в то время как строка '12'<'5' т.к. сравнение строк производится посимвольно и '1'<'5'). Ключ -r означает изменения порядка сортировки — с возрастающего на убывающий.
Команда head выводит несколько первых строк поступающего на ее вход потока, отбрасывая все остальные. Ключ -1 означает, что надо вывести только одну строку.
Таким образом, список пользовательских каталогов с их суммарным объемом арифметически сортируется по убыванию, и из полученного списка берется первая строка, т.е. строка с наибольшим числом, соответствующая самому объемному каталогу.
Использование команды tee:
sort text | tee sorted_text | head -n 1
Содержимое файла text сортируется, и результат сортировки записывается в файл sorted_text. Первая строка отсортированного текста выдается на экран.
Программы фильтры
В UNIX/Linux существует целый класс команд, которые принимают данные со стандартного потока ввода, каким-то образом обрабатывают их, и выдают результат на стандартный поток вывода. Такие программы называются программами-фильтрами.
Как правило, все эти программы работают как фильтры, если у них нет аргументов (опции могут быть), но как только им в качестве аргумента передаётся файл, они считывают данные из этого файла, а не со стандартного потока ввода (существуют и исключения, например, программа tr, которая обрабатывает данные поступающие исключительно через стандартный поток ввода).
полный список:
cat head tail cut sort uniq tee bc hexdump strings grep tr sed awk perl sh -s (Текст, который передаётся на стандартный поток ввода sh -s может интерпретироваться как последовательность команд shell. На выход передаётся результат их исполнения. ) ssh (Средство удалённого доступа ssh, может работать как фильтр. ssh подхватывает данные, переданные ему на стандартный поток ввода, передаёт их на удалённых хост и подаёт на вход процессу программы, имя которой было передано ему в качестве аргумента. Результат выполнения программы (то есть то, что она выдала на стандартный поток вывода) передаётся со стандартного вывода ssh.)
Подробнее в coreutils.
Именованные каналы
Безымянный канал можно построить только между процессами, которые порождены от одного процесса (и на практике они должны быть порождены одновременно, а не последовательно, хотя теоретически это не обязательно). Если же процессы имеют разных родителей, то между ними обычный, безымянный канал построить не получится.
Например, в данном случае d и e, и f и g легко могут быть соединены при помощи канала, но e и f соединить с помощью канала не получится.
Для решения этой задачи используются именованные каналы fifo (first in, first out). Они во всём повторяют обычные каналы (pipe), только имеют привязку к файловой системе. Создать именованный канал можно командой mkfifo:
mkfifo /tmp/fifo
Созданный канал можно использовать для соединения процессов между собой. Например, эти перенаправления будут работать одинаково:
f | g
и
f > /tmp/fifo & g < /tmp/fifo
e > /tmp/fifo& g < /tmp/fifo # в другом интерпретаторе
Потоки ввода/вывода и терминал
Большинство программ, которые работают с потоками ввода и вывода, работают с ними как с простыми файлами, и не рассчитывают на то, что поток подключен к терминалу. Но не все. Если потоки ввода/вывода отключаются от терминала и перенаправляются в файл, часть возможностей программы может пропасть.
Например, если командный интерпретатор отвязать от терминала, то у него потеряется множество интерактивных возможностей:
cat | sh -i | cat
Например, возможности прокручивать историю команд у него теперь нет. Возможности по редактированию теперь тоже сильно урезаны. Фактически, редактирование команды теперь выполняется уже с помощью программы cat, которая держит терминал, а интерпретатору поступают уже полностью введённые команды.
Проверить, подключен ли наш стандартный поток к терминалу, или он перенаправлен в файл, можно при помощи test, ключ -t:
test -t 0 && echo terminal terminal cat | test -t 0 && echo terminal cat | test -t 0 || echo file file <code> ===== Подстановка процесса ===== Есть хитрый трюк, который в чистом виде перенаправлением потока ввода/вывода не является, но имеет к нему отношение — подстановка процесса. Результат выполнения процесса можно представить в виде воображаемого файла и передать его другому процессу. Форма вызова: <code> команда1 <(команда2)
При таком вызове процессу команда1 передаётся файл (созданный налету канал или файл /dev/fd/…), в котором находятся данные, которые выводит команда2.
Например, у вас есть два файла с различными словами по одному в строке. Вы хотите определить, какие из них встречаются в одном файле, но не встречаются во втором. И наоборот.
cat f1 a b c b b cat f2 a c c c diff <(sort -u f1) <(sort -u f2) 2d1 < b
Получается, что в первом файле присутствует слово, которое отсутствует во втором (слово b).
Перенаправление вывода скрипта
Потоки ввода/вывода скрипта, исполняющегося сейчас, изнутри самого скрипта можно следующим образом:
exec > file exec 2>&1
Поменять местами потоки
Поменять местами стандартный поток вывода и стандартный поток ошибок
cmd 3>&2 2>&1 1>&3
Просмотр прогресса
Просмотр прогресса и скорости обработки данных в потоке.
Если пропустить данные, передающиеся в канале, через программу pv, то будет видна скорость обработки, время в течение которого работает канал и, если известно сколько данных должно быть обработано, приблизительное время окончания выполнения.
pv /tmp/shre.tar.gz | tar xz 62MB 0:00:18 [12,6MB/s] [==> ] 10% ETA 0:02:27


