Выбрать главу

           # удаляйте его потом командой rm * !

$ rm Glava0\[3\,8\] # удалит файл с именем Glava0[3,8],

                    # а не Glava03 и Glava08.

3.4.6. Потоки ввода-вывода

Как я уже сказал, каждому процессу сопоставлена таблица открытых им файлов. Три первых позиции в этой таблице заняты всегда: каждый процесс открывает потоки (помните, что в UNIX файл — это и есть поток данных?) для ввода и вывода данных, а также вывода сообщений об ошибках и другой диагностической информации. Эти потоки:

♦ 0 — стандартный ввод (stdin),

♦ 1 — стандартный вывод (stdout),

♦ 2 — стандартный поток сообщений об ошибках (stderr).

Ссылаться на эти потоки можно по их файловым дескрипторам. 0, 1 и 2 — это и есть такие дескрипторы.

По умолчанию потоки ввода-вывода связываются с консолью, с которой запущен процесс: стандартный ввод — с клавиатурой, другие два потока — с экраном (рис. 3.5, потоки cmd1).

Все потоки можно перенаправить в другой файл. Это может быть файл на диске, файл устройства (например, принтер или /dev/null) или стандартный поток другого процесса.

Для перенаправления стандартного вывода команды используется символ > («больше»). Если местом назначения служит файл, то можно его не перезаписывать, а присоединить (append) выводимые данные в его конец. Для такого перенаправления применяется символ >>.

Стандартный ввод перенаправляется символом < («меньше»).

Для перенаправления стандартного потока ошибок используется конструкция 2>. Чтобы присоединить stderr к stdout и перенаправить их вместе, пользуйтесь переадресацией 2>&1.

Для направления стандартного вывода одной команды на стандартный ввод другой применяется символ | — уже знакомый вам конвейер.

Ситуация, изображенная на рис. 3.5, могла бы сложиться после выполнения следующих команд:

cmd2 < file1.txt | cmd3 2>&1 > file2.txt

cmd4 2> /dev/null | tee file3.txt file4.txt file5.txt

Рис. 3.5. Перенаправление потоков ввода-вывода

Команда-фильтр tee копирует данные со своего стандартного ввода в стандартный вывод, дублируя их при этом в указанные ей файлы.

3.4.7. Группировка команд

Кроме конвейеров, команды можно соединять в списки. Простейший вид списка — несколько команд, разделенных точкой с запятой:

$ lpr myfile.txt ; lpq

Команды в таком списке выполняются последовательно: сначала будет выполнена команда постановки задания в очередь печати, а потом проверено состояние принтера. Оболочка ждет завершения каждой команды, чтобы отправить на выполнение следующую (синхронный режим).

В списки можно группировать не только одиночные команды, но и конвейеры:

$ ps -ef | head -n 1; ps -ef | grep httpd

UID    PID   PPID  С STIME TTY TIME     CMD

root   13565 1     0 13:11 ?   00:00:00 /usr/local/sbin/httpd

nobody 13566 13565 0 13:11 ?   00:00:00 /usr/local/sbin/httpd

nobody 13567 13565 0 13:11 ?   00:00:00 /usr/local/sbin/httpd

nobody 13642 13565 0 13:16 ?   00:00:00 /usr/local/sbin/httpd

Первый конвейер вырезает из списка процессов заголовок, а второй — информацию о демоне httpd.

Если требуется запустить команду на заднем плане и не ждать ее выполнения (асинхронный режим), то нужно завершить ее управляющим оператором &:

$ du --human-readable --total /home > diakusage.txt &

Команда du сообщает, сколько места на диске занято файлами в указанном каталоге. Обратите внимание на ключи: их имена предваряются не одним минусом, а двумя. Большинство команд поддерживает как короткие однобуквенные ключи, так и длинные — с осмысленными, легко запоминаемыми именами. Напоминаю, что список и значения ключей команды cmd можно получить, выполнив ее с ключом --help или --usage.

Конвейеры (или одиночные команды) в списке можно соединять управляющими операторами && и ||, получая «список И» или «список ИЛИ» соответственно:

cmd1 && cmd2 cmd3 || cmd4

Вторая команда в «списке И» будет выполнена только в случае успешного завершения первой. Типичный пример — создание каталога и переход в него:

$ mkdir mydir && cd mydir

Вторая команда в «списке ИЛИ» будет выполнена только в случае неуспешного завершения первой (возврата ею ненулевого значения):

$ my_command || echo "Команда my_command не найдена" | mail den

Вторая команда (конвейер) в этом примере формирует и посылает письмо с отчетом о неуспехе пользователю den.

Чтобы перенаправить в файл вывод всех команд из списка, нужно взять весь список в круглые скобки:

$ ( date; free; who; ) > logfile

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

$ pwd; ( cd / tmp ; pwd ) ; pwd;

/home/den

/tmp

/home/den

$

Если нужно часто выполнять одну и ту же последовательность команд, можно оформить ее как функцию:

$ function morning_report {

> date;

> free;

> W;

> }

$ morning_report | mail root

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

Определенные вами переменные и функции действительны только для текущего сеанса работы в оболочке bash. Чтобы воспользоваться ими в следующем сеансе, запишите их в текстовый файл, а когда они понадобятся, загрузите этот файл в память командного интерпретатора встроенной командой source:

$ cat > foo

myvar="Моя переменная"

function myfun {

 echo $myvar

}

^D

$ source foo

$ myfun

Моя переменная

$

Команда source выполняет инструкции, содержащиеся в файле, в текущей оболочке в отличие от исполнения файла, содержащего сценарий: тот выполняется в дочерней оболочке, и определенные в ней переменные и функции для родительской оболочки невидимы. Чтобы заметить разницу, удалите переменную myvar и функцию myfun из памяти оболочки командой unset, сделайте файл foo исполняемым командой chmod (п.3.4.3) и исполните его. Убедитесь, что после его выполнения переменная myvar и функция myfun остались не определены.

3.4.8. Инициализационные файлы bash

Начальные значения переменных окружения становятся известны командному интерпретатору bash из инициализационных файлов, которые он прочитывает сразу после своего запуска. Эти файлы называются .bash_profile и .bashrc (в порядке чтения оболочкой) и берутся из домашнего каталога запустившего оболочку пользователя.