KnigaRead.com/
KnigaRead.com » Компьютеры и Интернет » Программирование » Мендель Купер - Искусство программирования на языке сценариев командной оболочки

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

На нашем сайте KnigaRead.com Вы можете абсолютно бесплатно читать книгу онлайн Мендель Купер, "Искусство программирования на языке сценариев командной оболочки" бесплатно, без регистрации.
Перейти на страницу:

echo "Вывод команды "ls -al""

echo

ls -al

echo; echo

echo "Вывод команды "df""

echo

df


# ----------------------------------------------------------- #


exec 1>&6 6>&- # Восстановить stdout и закрыть дескр. #6.


echo

echo "== stdout восстановлено в значение по-умолчанию == "

echo

ls -al

echo


exit 0

Пример 16-3. Одновременное перенаправление устройств, stdin и stdout, с помощью команды exec

#!/bin/bash

# upperconv.sh

# Преобразование символов во входном файле в верхний регистр.


E_FILE_ACCESS=70

E_WRONG_ARGS=71


if [ ! -r "$1" ] # Файл доступен для чтения?

then

echo "Невозможно прочитать из заданного файла!"

echo "Порядок использования: $0 input-file output-file"

exit $E_FILE_ACCESS

fi # В случае, если входной файл ($1) не задан

#+ код завершения будет этим же.


if [ -z "$2" ]

then

echo "Необходимо задать выходной файл."

echo "Порядок использования: $0 input-file output-file"

exit $E_WRONG_ARGS

fi


exec 4<&0

exec < $1 # Назначить ввод из входного файла.


exec 7>&1

exec > $2 # Назначить вывод в выходной файл.

# Предполагается, что выходной файл доступен для записи

# (добавить проверку?).


# -----------------------------------------------

cat - | tr a-z A-Z # Перевод в верхний регистр

# ^^^^^ # Чтение со stdin.

# ^^^^^^^^^^ # Запись в stdout.

# Однако, и stdin и stdout были перенаправлены.

# -----------------------------------------------


exec 1>&7 7>&- # Восстановить stdout.

exec 0<&4 4<&- # Восстановить stdin.


# После восстановления, следующая строка выводится на stdout, чего и следовало ожидать.

echo "Символы из "$1" преобразованы в верхний регистр, результат записан в "$2"."


exit 0


16.2. Перенаправление для блоков кода

Блоки кода, такие как циклы while, until и for, условный оператор if/then, так же могут смешиваться с перенаправлением stdin. Даже функции могут использовать эту форму перенаправления (см. Пример 22-7). Оператор перенаправления <, в таких случаях, ставится в конце блока.

Пример 16-4. Перенаправление в цикл while

#!/bin/bash


if [ -z "$1" ]

then

Filename=names.data # По-умолчанию, если имя файла не задано.

else

Filename=$1

fi

# Конструкцию проверки выше, можно заменить следующей строкой (подстановка параметров):

#+ Filename=${1:-names.data}


count=0


echo


while [ "$name" != Smith ] # Почему переменная $name взята в кавычки?

do

read name # Чтение из $Filename, не со stdin.

echo $name

let "count += 1"

done <"$Filename" # Перенаправление на ввод из файла $Filename.

# ^^^^^^^^^^^^


echo; echo "Имен прочитано: $count"; echo


# Обратите внимание: в некоторых старых командных интерпретаторах,

#+ перенаправление в циклы приводит к запуску цикла в субоболочке (subshell).

# Таким образом, переменная $count, по окончании цикла, будет содержать 0,

# значение, записанное в нее до входа в цикл.

# Bash и ksh стремятся избежать запуска субоболочки (subshell), если это возможно,

#+ так что этот сценарий, в этих оболочках, работает корректно.

#

# Спасибо Heiner Steven за это примечание.


exit 0

Пример 16-5. Альтернативная форма перенаправления в цикле while

#!/bin/bash


# Это альтернативный вариант предыдущего сценария.


# Предложил: by Heiner Steven

#+ для случаев, когда циклы с перенаправлением

#+ запускаются в субоболочке, из-за чего переменные, устанавливаемые в цикле,

#+ не сохраняют свои значения по завершении цикла.


if [ -z "$1" ]

then

Filename=names.data # По-умолчанию, если имя файла не задано.

else

Filename=$1

fi


exec 3<&0 # Сохранить stdin в дескр. 3.

exec 0<"$Filename" # Перенаправить stdin.


count=0

echo


while [ "$name" != Smith ]

do

read name # Прочитать с перенаправленного stdin ($Filename).

echo $name

let "count += 1"

done <"$Filename" # Цикл читает из файла $Filename.

# ^^^^^^^^^^^^


exec 0<&3 # Восстановить stdin.

exec 3<&- # Закрыть временный дескриптор 3.


echo; echo "Имен прочитано: $count"; echo


exit 0

Пример 16-6. Перенаправление в цикл until

#!/bin/bash

# То же самое, что и в предыдущем примере, только для цикла "until".


if [ -z "$1" ]

then

Filename=names.data # По-умолчанию, если файл не задан.

else

Filename=$1

fi


# while [ "$name" != Smith ]

until [ "$name" = Smith ] # Проверка != изменена на =.

do

read name # Чтение из $Filename, не со stdin.

echo $name

done <"$Filename" # Перенаправление на ввод из файла $Filename.

# ^^^^^^^^^^^^


# Результаты получаются теми же, что и в случае с циклом "while", в предыдущем примере.


exit 0

Пример 16-7. Перенаправление в цикл for

#!/bin/bash


if [ -z "$1" ]

then

Filename=names.data # По-умолчанию, если файл не задан.

else

Filename=$1

fi


line_count=`wc $Filename | awk '{ print $1 }'`

# Число строк в файле.

#

# Слишком запутано, тем не менее показывает

#+ возможность перенаправления stdin внутри цикла "for"...

#+ если вы достаточно умны.

#

# Более короткий вариант line_count=$(wc < "$Filename")


for name in `seq $line_count` # "seq" выводит последовательность чисел.

# while [ "$name" != Smith ] -- более запутанно, чем в случае с циклом "while" --

do

read name # Чтение из файла $Filename, не со stdin.

echo $name

if [ "$name" = Smith ]

then

break

fi

done <"$Filename" # Перенаправление на ввод из файла $Filename.

# ^^^^^^^^^^^^


exit 0

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

Пример 16-8. Перенаправление устройств (stdin и stdout) в цикле for

#!/bin/bash


if [ -z "$1" ]

then

Filename=names.data # По-умолчанию, если файл не задан.

else

Filename=$1

fi


Savefile=$Filename.new # Имя файла, в котором сохраняются результаты.

FinalName=Jonah # Имя, на котором завершается чтение.


line_count=`wc $Filename | awk '{ print $1 }'` # Число строк в заданном файле.


for name in `seq $line_count`

do

read name

echo "$name"

if [ "$name" = "$FinalName" ]

then

break

fi

done < "$Filename" > "$Savefile" # Перенаправление на ввод из файла $Filename,

# ^^^^^^^^^^^^^^^^^^^^^^^^^^^ и сохранение результатов в файле.


exit 0

Пример 16-9. Перенаправление в конструкции if/then

#!/bin/bash


if [ -z "$1" ]

then

Filename=names.data # По-умолчанию, если файл не задан.

else

Filename=$1

fi


TRUE=1


if [ "$TRUE" ] # конструкции "if true" и "if :" тоже вполне допустимы.

then

read name

echo $name

fi <"$Filename"

# ^^^^^^^^^^^^


# Читает только первую строку из файла.


exit 0

Пример 16-10. Файл с именами "names.data", для примеров выше

Aristotle

Belisarius

Capablanca

Euler

Goethe

Hamurabi

Jonah

Laplace

Maroczy

Purcell

Schmidt

Semmelweiss

Smith

Turing

Venn

Wilson

Znosko-Borowski


# Это файл с именами для примеров

#+ "redir2.sh", "redir3.sh", "redir4.sh", "redir4a.sh", "redir5.sh".

Перенаправление stdout для блока кода, может использоваться для сохранения результатов работы этого блока в файл. См. Пример 3-2.

Встроенный документ -- это особая форма перенаправления для блоков кода.


16.3. Область применения

Как один из вариантов грамотного применения перенаправления ввода/вывода, можно назвать разбор и "сшивание" вывода от команд (см. Пример 11-6). Это позволяет создавать файлы отчетов и журналов регистрации событий.

Пример 16-11. Регистрация событий

#!/bin/bash

# logevents.sh, автор: Stephane Chazelas.


# Регистрация событий в файле.

# Сценарий должен запускаться с привилегиями root (что бы иметь право на запись в /var/log).


ROOT_UID=0 # Привилегии root имеет только пользователь с $UID = 0.

E_NOTROOT=67 # Код завершения, если не root.


if [ "$UID" -ne "$ROOT_UID" ]

then

echo "Сценарий должен запускаться с привилегиями root."

exit $E_NOTROOT

fi


FD_DEBUG1=3

FD_DEBUG2=4

FD_DEBUG3=5


# Раскомментарьте одну из двух строк, ниже, для активизации сценария.

# LOG_EVENTS=1

# LOG_VARS=1


log() # Запись даты и времени в файл.

{

echo "$(date) $*" >&7 # Добавляет в конец файла.

# См. ниже.

}


case $LOG_LEVEL in

1) exec 3>&2 4> /dev/null 5> /dev/null;;

2) exec 3>&2 4>&2 5> /dev/null;;

3) exec 3>&2 4>&2 5>&2;;

*) exec 3> /dev/null 4> /dev/null 5> /dev/null;;

esac


FD_LOGVARS=6

if [[ $LOG_VARS ]]

then exec 6>> /var/log/vars.log

else exec 6> /dev/null # Подавить вывод.

fi


FD_LOGEVENTS=7

if [[ $LOG_EVENTS ]]

then

# then exec 7 >(exec gawk '{print strftime(), $0}' >> /var/log/event.log)

# Строка, выше, не работает в Bash, версии 2.04.

exec 7>> /var/log/event.log # Добавление в конец "event.log".

log # Записать дату и время.

Перейти на страницу:
Прокомментировать
Подтвердите что вы не робот:*