Для программирования сценариев на языке командного интерпретатора одной из важнейших его способностей является возможность организации сохранения результатов в файлы и возможность считывания исходных данных из файлов при выполнении команд.
командный интерпретатор организует перенаправления потоков ввода-вывода внешних и встроенных команд при помощи конструкций [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-го пользователей.
Содержимое
- Перенаправление стандартного потока вывода
- Перенаправление стандартного потока ошибок
- Подавление стандартного потока ошибок
- Перенаправление стандартного потока ввода
- Конвейерная обработка: отправка списка установленных пакетов по электронной почте
- Конвейерная обработка: подсчет количества пустых файлов
- Конвейерная обработка: вывод части файла
- Конвейерная обработка: генерация трех случайных восьмизначных паролей
- Конвейерная обработка: удаление пустых файлов
- Конвейерная обработка: просмотр группового членства пользователей системы
- Конвейерная обработка: параллельная упаковка ISO-образов
Перенаправление стандартного потока вывода
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