После этого, командная оболочка наследует эти три дескриптора, и любая команда, запускаемая в этой оболочке, так же наследует их. Термин перенаправление -- означает переназначение одного файлового дескриптора на другой (канал (конвейер) или что-то другое). Переназначение может быть выполнено локально (для отдельной команды, для группы команд, для подоболочки, для операторов while, if, case, for...) или глобально (с помощью exec).
ls > /dev/null-- означает запуск команды lsс файловым дескриптором 1, присоединенным к устройству /dev/null.
bash$ lsof -a -p $$ -d0,1,2
COMMAND PID USER FD TYPE DEVICE SIZE NODE NAME
bash 363 bozo 0u CHR 136,1 3 /dev/pts/1
bash 363 bozo 1u CHR 136,1 3 /dev/pts/1
bash 363 bozo 2u CHR 136,1 3 /dev/pts/1
bash$ exec 2> /dev/null
bash$ lsof -a -p $$ -d0,1,2
COMMAND PID USER FD TYPE DEVICE SIZE NODE NAME
bash 371 bozo 0u CHR 136,1 3 /dev/pts/1
bash 371 bozo 1u CHR 136,1 3 /dev/pts/1
bash 371 bozo 2w CHR 1,3 120 /dev/null
bash$ bash -c 'lsof -a -p $$ -d0,1,2' | cat
COMMAND PID USER FD TYPE DEVICE SIZE NODE NAME
lsof 379 root 0u CHR 136,1 3 /dev/pts/1
lsof 379 root 1w FIFO 0,0 7118 pipe
lsof 379 root 2u CHR 136,1 3 /dev/pts/1
bash$ echo "$(bash -c 'lsof -a -p $$ -d0,1,2' 2>&1)"
COMMAND PID USER FD TYPE DEVICE SIZE NODE NAME
lsof 426 root 0u CHR 136,1 3 /dev/pts/1
lsof 426 root 1w FIFO 0,0 7520 pipe
lsof 426 root 2w FIFO 0,0 7520 pipe
Упражнение:Проанализируйте следующий сценарий.
#! /usr/bin/env bash
mkfifo /tmp/fifo1 /tmp/fifo2
while read a; do echo "FIFO1: $a"; done < /tmp/fifo1 &
exec 7> /tmp/fifo1
exec 8> >(while read a; do echo "FD8: $a, to fd7"; done >&7)
exec 3>&1
(
(
(
while read a; do echo "FIFO2: $a"; done < /tmp/fifo2 | tee /dev/stderr | tee /dev/fd/4 | tee /dev/fd/5 | tee /dev/fd/6 >&7 &
exec 3> /tmp/fifo2
echo 1st, to stdout
sleep 1
echo 2nd, to stderr >&2
sleep 1
echo 3rd, to fd 3 >&3
sleep 1
echo 4th, to fd 4 >&4
sleep 1
echo 5th, to fd 5 >&5
sleep 1
echo 6th, through a pipe | sed 's/.*/PIPE: &, to fd 5/' >&5
sleep 1
echo 7th, to fd 6 >&6
sleep 1
echo 8th, to fd 7 >&7
sleep 1
echo 9th, to fd 8 >&8
) 4>&1 >&3 3>&- | while read a; do echo "FD4: $a"; done 1>&3 5>&- 6>&-
) 5>&1 >&3 | while read a; do echo "FD5: $a"; done 1>&3 6>&-
) 6>&1 >&3 | while read a; do echo "FD6: $a"; done 3>&-
rm -f /tmp/fifo1 /tmp/fifo2
# Выясните, куда переназначены файловые дескрипторы каждой команды и подоболочки.
exit 0
Приложение E. Локализация
Возможность локализации сценариев Bash нигде в документации не описана.
Локализованные сценарии выводят текст на том языке, который используется системой, в соответствии с настройками. Пользователь Linux, живущий в Берлине (Германия), будет видеть сообщения на немецком языке, в то время как другой пользователь, проживающий в Берлине штата Мэриленд (США) -- на английском.
Для создания локализованых сценариев можно использовать следующий шаблон, предусматривающий вывод всех сообщений на языке пользователя (сообщения об ошибках, приглашения к вводу и т.п.).
#!/bin/bash
# localized.sh
E_CDERROR=65
error()
{
printf "$@" >&2
exit $E_CDERROR
}
cd $var || error $"Can't cd to %s." "$var"
read -p $"Enter the value: " var
# ...
bash$ bash -D localized.sh
"Can't cd to %s."
"Enter the value: "
Это список всех текстовых сообщений, которые подлежат локализации. (Ключ -D выводит список строк в двойных кавычках, которым предшествует символ $, без запуска сценария на исполнение.)
bash$ bash --dump-po-strings localized.sh
#: a:6
msgid "Can't cd to %s."
msgstr ""
#: a:7
msgid "Enter the value: "
msgstr ""
Ключ --dump-po-strings в Bash напоминает ключ -D, но выводит строки в формате "po", с помощью утилиты gettext.
Теперь построим файл language.po, для каждого языка, на которые предполагается перевести сообщения сценария. Например:
Файл ru.po сделан переводчиком, в оригинальном документе локализация выполнена на примере французского языка
ru.po:
#: a:6
msgid "Can't cd to %s."
msgstr "Невозможно перейти в каталог %s."
#: a:7
msgid "Enter the value: "
msgstr "Введите число: "
Затем запустите msgfmt.
msgfmt -o localized.sh.mo ru.po
Перепишите получившийся файл localized.sh.mo в каталог /usr/share/locale/ru/LC_MESSAGES и добавьте в начало сценария строки:
TEXTDOMAINDIR=/usr/share/locale
TEXTDOMAIN=localized.sh
Если система корректно настроена на русскую локаль, то пользователь, запустивший сценарий, будет видеть сообщения на русском языке.
В старых версиях Bash или в других командных оболочках, потребуется воспользоваться услугами утилиты gettext, с ключом -s. В этом случае наш сценарий будет выглядеть так:
#!/bin/bash
# localized.sh
E_CDERROR=65
error() {
local format=$1
shift
printf "$(gettext -s "$format")" "$@" >&2
exit $E_CDERROR
}
cd $var || error "Can't cd to %s." "$var"
read -p "$(gettext -s "Enter the value: ")" var
# ...
А переменные TEXTDOMAIN и TEXTDOMAINDIR, необходимо будет экспортировать в окружение.
---
Автор этого приложения: Stephane Chazelas.
Приложение F. История команд
Командная оболочка Bash предоставляет в распоряжение пользователя инструментарий командной строки, позволяющий управлять историей команд . История команд -- это, прежде всего, очень удобный инструмент, сокращающий ручной ввод.
Читать дальше