Перенаправление потоков ввода-вывода Linux

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

командный интерпретатор организует перенаправления потоков ввода-вывода внешних и встроенных команд при помощи конструкций [n]>file или [n]>>file и [n]<file. Символы < и > естественным образом идентифицируют направление выполняемых перенаправлений — ввода или вывода, а необязательное число n уточняет номер перенаправляемого потока (при умалчивании n перенаправляется стандартный поток вывода № 1, stdout при выводе и стандартный поток ввода № 0, stdin при вводе). Перенаправление вывода > выполняется с усечением старого содержимого, а перенаправление >> — с добавлением к старому содержимому файла file.

Для перенаправления заданного потока N некоторой запускаемой команды command в файл file командный интерпретатор порождает дочерний процесс при помощи системного вызова fork, затем в новом процессе открывает файл file при помощи системного вызова open, перенаправляет поток N в открытый файл посредством системного вызова dup2 и, наконец, запускает в этом процессе программу command при помощи системного вызова execve.

В примере из листинга ниже при помощи «разрезателя» текста cut вырезается по разделителю (-d) : (двоеточие) 10-е поле (-f) файла passwd, содержащего свойства учетных записей пользователей, зарегистрированные в системе, а результат сохраняется в файле users при помощи перенаправления потока STDOUT. Затем, при помощи потокового редактора файлов sed выводятся (5,8р) только (-n) с 5-й по 8-ю строки полученного файла, что дает логины с 5-го по 8-го пользователей.

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

bender@ubuntu:~$ sed -n 5,8р /etc/passwd

sync: х: 4:65534: sync: /bin: /bin/sync

games :х: 5:60: games: /usr/games: /bin/sh

man: х: 6:12: man: /var/cache/man: /bin/sh

lp: x: 7:7: lp: /var/spool/lpd: /bin/sh

bender@ubuntu:~$ cut -f 1 -d : /etc/passwd 1> users

bender@ubuntu:~$ sed -n 5,8p users

sync

games

man

lp

При выполнении некоторых команд, например как в листинге ниже, при поиске файлов посредством find может выводиться достаточное количество сообщений об «ошибках» доступа в тот или иной каталог, которые мешают анализировать результаты поиска.

В этом случае их удобно убрать с терминала путем перенаправления потока № 2, stderr, например, в файл eaccess. В результате на терминале будут отражены только имена (-name) файлов, соответствующие критерию имени *.xml, найденные в каталоге /etc и всех его подкаталогах.

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

bender@ubuntu:~$ find /etc -name ‘*.xml’

/etc/obex-data — server/imaging_capabilities. xml

find: ‘/etc/lvm/backup’: Отказано в доступе

find: ‘/etc/lvm/cache1: Отказано в доступе

find: ‘/etc/cups/ssl’: Отказано в доступе

/etc/ImageMagick/log. xml

bender@ubuntu:~$ find /etc -name ‘*.xml’ 2>eaccess

/etc/obex-data-server/imaging_capabilities.xml

/etc/ImageMagick/log. xml

На практике часто оказывается; что мешающий вывод сообщений об «ошибках» доступа, как в листинге ниже, оказывается ненужным вовсе, тогда его подавляют при помощи перенаправления потока STDERR в файл /dev/null специального всепожирающего псевдоустройства null.

Подсчитав количество строк (-l) в результирующем файле empty и зная, что одна строка в нем соответствует одному найденному ранее командой find имени файла, размер (-size) которого равен 0 байт, можно получить количество «пустых» файлов в системе.

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

bender@ubuntu: ~$ find / -size 0 1>empty 2>/dev/null

bender@ubuntu:~$ wc -l empty

90521 empty

В случаях, когда необходимо использовать содержимое файла в качестве исходных данных для выполнения -программ, вместо ввода этих данных с терминала, как в примере из листинга ниже, применяют перенаправление потока STDIN. Таким образом, например, сохраненный в файл весьма внушительный список установленных в системе пакетов (полученный командой dpkg) можно отправить по почте командой mail в качестве текста сообщения.

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

bender@ubuntu:~$ dpkg -l > installed-pacakges

bender@ubuntu:~$ mail alevin@gmail.com 0< installed-pacakges

bender@ubuntu:~$ rm -f installed-pacakges

Однако чаще на практике необходимо использовать результат выполнения одной команды в качестве исходных данных другой команды, не сохраняя, эти данные в промежуточный (ненужный) файл. В. этом случае используют конструкциюcommand1 | command2 | называемую конвейерной обработкой (или просто конвейером, или каналом (pipe), или даже трубой).

Нужно заметить, конструкцией конвейерной обработки можно сцеплять более чем две команды, причем все они будут выполняться параллельно в дочерних процессах командного интерпретатора. При этом стандартные потоки ввода и вывода пар процессов будут связаны простейшим средством IPC, реализуемым ядром ОС — неименованным каналом, создаваемым системным вызовом pipe, куда и будут перенаправлены потоки команд при помощи системного вызова dup2.

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

Конвейерная обработка: отправка списка установленных пакетов по электронной почте

bender@ubuntu:~$ dpkg -l | mail alevin@gmail.com

Конвейерная обработка: подсчет количества пустых файлов

bender@ubuntu:~$ find / -size 0 2>/dev/null | wc -l

91715

 

Конвейерная обработка: вывод части файла

bender@ubuntu:~$ getent passwd | cut -f 1 -d : | head -8 | tail -5

sys
sync
games
man
lp

В примере из листинга выше конвейерная обработка используется для последовательного получения строкового представления свойств всех доступных пользовательских учетных записей при помощи getent, затем вырезания из этих строк при помощи cut 1-го поля (-f) посредством разделителя : (-d), далее выбора 8-ми первых строк командой head, а потом выбора 5-ти последних строк предыдущего результата командой tail. Учетные записи пользователей, зарегистрированных непосредственно в системе (локально), хранятся в файле /etc/passwd. Все доступные в системе учетные записи, в том числе, например, централизованные в (сетевых) LDAP-каталогах организации, могут быть получены при помощи команды getent благодаря службе имен.

Конвейерная обработка: генерация трех случайных восьмизначных паролей

bender@ubuntu:~$ tr -dc a-zA-ZO-9 </dev/urandom | fold -w 8 | head -3

QCh67VnC

3nwAG7P9

51IС1Lxz

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

Для этого из специального файла псевдоустройства urandom, генерирующего случайную последовательность байтов, отбираются командой транслитерации tr только строковые и заглавные буквы латинского алфавита и цифры a-zA-z0-9 путем удаления (-d) из выходного потока символов, не () попавших в заданный набор. Затем команда fold разбивает свой входной поток по 8 символов в строке выходного потока, после чего команда head выбирает только 3 первые строки.

Конвейерная обработка: удаление пустых файлов

bender@ubuntu:~$ find /tmp -user bender -size 0 -print0 2>/dev/null | xargs -0 rm -f

В листинге выше конвейерная обработка вместе с командой xargs используется для того, чтобы во временном каталоге /tmp удалить все файлы, принадлежащие (-user) пользователю bender, размер (-size) которых равен нулю. Сначала при помощи команды find производится поиск файлов согласно указанным критериям и вывод списка их имен с разделением имен нулевым символом (-print).

Затем команда xargs последовательно «применяет» команду rm безусловного (-f) удаления файла для каждого имени из списка. Следует отметить, что такая конструкция работает с абсолютно любыми именами файлов, включая файлы с пробелами, табуляциями, переводами строк и другими управляющими символами в имени, т. к. имена файлов в списке разделяются нулевым символом, а он единственный запрещен к использованию в именах файлов.

Аналогично, в листинге ниже, используя конвейер, при помощи команды groups можно вывести групповое членство всех пользователей, доступных в системе.

Конвейерная обработка: просмотр группового членства пользователей системы

bender@ubuntu:~$ getent passwd | cut -f 1 -d : | xargs groups

john : john candy

mike : mike

bubble : bubble candy

fitz : fitz sudo

skillet : skillet

bender : bender

С помощью конвейеров и универсального спискового «применятеля» команд xargs можно организовать  параллельный запуск (-Р) упаковки целого списка отобранных командой find файлов, использовав параллельный упаковщик pbzip2, в несколько упаковочных нитей () на каждый файл. В результате получим запускаемые парами процессы по две активные нити на каждый, что эффективно загружает четырехъядерный процессор в течение упаковки всего списка файлов.

Конвейерная обработка: параллельная упаковка ISO-образов

bender@ubuntu: ~$ find . -name ‘*.iso’ ( xargs -P 2 pbzip2 -p2 &

bender@ubuntu: ~$ ps f

PID    TTY     STAT        TIME     COMMAND
4723      pts/1    S                0:00      -bash
4903      pts/1    S               0:00        \_ xargs -P 2 -nl pbzip2 -p2
4904      pts/1    Sl              0:08,       |       \_ pbzip2 -p2 ./dvd.itso
4905      pts/1    Sl              0:08        |       \_ pbzip2 -p2 ./plan9.iso
4856      pts/1    R+            0:00        \_ ps f
bender@ubuntu: ~$ ps -fL
UID       PID  PPID LWP C NLWP  STIME TTY       TIME      CMD
bender 4723 4722 4723    0   1         01:18    pts/1 00:00:00 -bash
bender 4903 4723 4903   0   1         01:21    pts/1 00:00:00 xargs -P 2 -nl pbztp2
bender 4904 4903 4910  99  6        01:21     pts/1 00:00:01 pbzip2 -p2 ./dvd.tso
bender 4904 4903 4913  99  6        01:21     pts/1 00:00:01 pbztp2 -p2 ./dvd.tso
bender 4904 4903 4914   0   6        01:21     pts/1 00:00:00 pbztp2 -p2 ./dvd.tso
bender 4905 4903 4911   99  0        01:21    pts/1 00:00:01 pbztp2 -p2 ./plan9.ts
bender 4905 4903 4912  99  6         01:21    pts/1 00:00:01 pbztp2 -p2 ./plan9.ts
bender 4905 4903 4915   0   6         01:21    pts/1 00:00:00 pbztp2 -p2 ./plan9.ts
bender 4916 4723 4916    0   1         01:21     pts/1 00:00:00 ps -fL

 

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