Меню Рубрики

Stdin stderr stdout linux

Работа с потоками STDIN, STDOUT, STDERR

Виды потоков

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

  • STDIN (Номер файлового дескриптора — 0)
    Стандартный входной поток. Канал принимающий данные для обработки и последующей передачи на канал STDOUT и/или STDERR.
  • STDOUT (Номер файлового дескриптора — 1)
    Стандартный выходной поток. Представляет собой канал записи результатов выполнения каких-либо процессов.
  • STDERR (Номер файлового дескриптора — 2)
    Стандартный выходной поток ошибок. В данный канал попадают сообщения об ошибках.

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

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

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

find / -name core > /tmp/testfile

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

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

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

  • >> — вывод STDOUT в конец файла.

find / -name core >> /tmp/testfile

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

Запись STDOUT в конец файла

  • >& — вывод STDOUT и STDERR в файл

find / -name core >& /tmp/testfile

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

Объединение выходных потоков

  • 2> — вывод STDERR в файл

find / -name core 2> /tmp/testfile

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

Вывод STDERR

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

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

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

Для того чтобы направить выходной поток одной команды на входной поток другой, применяют символ — | (pipe).

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

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

Заключение

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

Понравилась статья? Расскажите о ней друзьям!

Источник

Потоки данных

Статья посвящена работой с потоками данных в 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. Читаем его:

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

Теперь попробуем направить stderr команды rm:

Здесь мы использовали номер потока stderr (2). По умолчанию оператор > перенаправляет поток stdout, который имеет номер 1. Чтобы направить другой поток, надо перед оператором > поставить его номер.

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

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

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

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

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

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

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

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

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

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

Каждый может помочь развитию данной серии статей, поделиться своим опытом. Добро пожаловать: http://www.linuxman.ru. Все изменения в Вики я буду со временем переносить и в Хабр.

Ой, у вас баннер убежал!

Редакторский дайджест

Присылаем лучшие статьи раз в месяц

Скоро на этот адрес придет письмо. Подтвердите подписку, если всё в силе.

Похожие публикации

Bash-скрипты, часть 10: практические примеры

Bash-скрипты, часть 9: регулярные выражения

Bash-скрипты, часть 8: язык обработки данных awk

Курсы

AdBlock похитил этот баннер, но баннеры не зубы — отрастут

Комментарии 43

А по-моему, вполне понятно все написано в книжках. Разобраться совсем недолго… Примеры книг могу привести, если надо.

А так за статью(не считаем ошибки) респект. Немногие сейчас отваживаются их писать)

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

Неверно. Это сделает команда find .

Не забываем, что globbing (замена wildcards) происходит в шелле. И * по умолчанию не расширяется на dot entries в текущем каталоге.

Нельзя не вспомнить про будильник настоящего юниксоида:

Настоящий юниксоид напишет так:

sleep 8h && cat /dev/urandom > /dev/dsp

Будет (собственно я не говорил, что Ваш код в корне не верен), но настоящий юниксоид напишет:
sleep 8h && cat /dev/urandom > /dev/dsp

Так как код:
sleep 8h; cat /dev/urandom > /dev/dsp
при отсутствии /bin/sleep сразу начнет звенеть…

Ваш пример довольно безобидный, но когда начинают писать
cd /dir1/dir2/dir3; rm *
становится страшно…

Спасибо за совет, но, прочитав мануал, я понял эту команду как:

tee [-ai] [file . ]
The tee utility copies standard input to standard output, making a copy
in zero or more files. The output is unbuffered.

cat ./file.txt | grep ‘key’ | tee ./file2.txt | grep ‘subkey’ > ./file3.txt

Как ./file2.txt направить не в физический файл, а в пайп, где я еще хочу сделать sort?

У тебя есть такой пример:

Извини, у меня нет цензурных слов. За такое я отрываю разработчикам руки. Такой код в скриптах — это бомба замедленного действия, она срабатывает редко, но неожиданно и разрушительно. О grep-е после find-а и xargs rm вместо -delete уже говорили, но это можно попытаться оправдать тем, что примеры учебные и искуственные. А вот опасность этого примера оправдать нельзя!

Автор, создай у себя, для эксперимента директорию где-нибудь в темпе:

В «документы» положи очень важные и ценные тебе документы. В «документы на удаление» — ерунду. А теперь выполни эту команду и сожалей, что директория «документы» исчезла. Не .svn в этой директории, а «документы» целиком!

Писать так — опасно, учить других писать так — во сто крат опасней! Читать маны перед написанием учебной статьи — напротив, не только неопасно, но и крайне полезно.

Угу, этот пример тоже хорош:

Такой же убийственный

Спасибо за дельный комментарий.
Но если все таки забыть про учебную составляющую и обратить внимание на саму задачу удаления каталогов .svn, то у меня возник вот какой вопрос: как же правильно написать команду?

У меня не получилось удалить каталоги .svn с использованием -delete, так как я создал там вложенные файлы (это часто бывает в реальной жизни в таком каталоге).

find. -type d -and -iname ‘.svn’ -delete
find: cannot delete `./документы/.svn’: Каталог не пуст

В конце концов появился вот такой вариант:

find. -type d -and -iname ‘.svn’ -execdir rm -Rf .svn \; 2>/dev/null

Есть ли более оптимальный?

Обычно пользуюсь find -print0 | xargs -0 . А только средствами find… попробуйте

find . -depth \( -path ‘*/.svn/*’ -or -iname ‘.svn’ \) -delete

Хотя поздновато уже, не ручаюсь.

find ищет по каким-то условиям и выполняет определённое действие с результатом поиска. Дело в том, что по умолчанию find делает -print, то есть выводит результат на стандартный вывод, разделяя имена переводом строки.
xargs читает со стандартного ввода записи, разделяя, их, среди прочего, и пробелами. Таким образом, если find найдёт файл с именем «раз два», то xargs запустит указанную команду с аргументами «раз» и «два». Нам нужно, чтобы find разделял записи разделителем, который не может присутствовать в именах файлов. Среди ext2/3 таких символов два — это нулевой символ (не имеет печатаемого обозначения) и символ прямого слэша. Прямой слэш, кажется, в некоторых файловых системах может являться частью имени файла, потому нам остаётся только нулевой символ.
Как сказано в мануале в первых строках по find: «you should probably consider using ‘-print0’ instead».
Действие -print0 заставляет find вывести на стандартный вывод результаты, разделяемые нулевым символом, а опция -0 у xargs заставляет в качестве разделителя записей принимать только нулевой символ.

В моём мане (это не сарказм, маны на разных системах бывают очень разные) есть такой пример для этого дела:

Что касается возможности запуска без xargs — для скриптов я бы посоветовал такую конструкцию:

Для применения вручную, после запуска без -delete и изучения списка:

При этом, файлы и директории типа .svnlalala тоже будут уничтожены, если присутствуют.

Источник

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

  • Правка pdf mac os
  • Правда ли mac os не подвержена вирусам
  • Пошаговая установка mac os на ноутбук
  • Почтовый сервер mac os
  • Почтовый клиент mail mac os