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

Пример 17-1. dummyfile: Создание 2-х строчного файла-заготовки

Пример 17-1. dummyfile: Создание 2-х строчного файла-заготовки

#!/bin/bash

# Неинтерактивное редактирование файла с помощью 'vi'.

# Эмуляция 'sed'.

E_BADARGS=65

if [ -z "$1" ]

then

echo "Порядок использования: `basename $0` filename"

exit $E_BADARGS

fi

TARGETFILE=$1

# Вставить 2 строки в файл и сохранить.

#--------Начало встроенного документа-----------#

vi $TARGETFILE <<x23LimitStringx23

i

Это строка 1.

Это строка 2.

^[

ZZ

x23LimitStringx23

#----------Конец встроенного документа-----------#

# Обратите внимание: ^[, выше -- это escape-символ

#+ Control-V <Esc>.

# Bram Moolenaar указывает, что этот скрипт может не работать с 'vim',

#+ из-за возможных проблем взаимодействия с терминалом.

exit 0

Этот сценарий, с тем же эффектом, мог бы быть реализован, основываясь не на vi, а на ex. Встроенные документы, содержащие команды для ex, стали настолько обычным делом, что их уже смело можно вынести в отдельную категорию -- ex-сценарии.

Пример 17-2. broadcast: Передача сообщения всем, работающим в системе, пользователям

#!/bin/bash

wall <<zzz23EndOfMessagezzz23

Пошлите, по электронной почте, ваш заказ на пиццу, системному администратору.

(Добавьте дополнительный доллар, если вы желаете положить на пиццу анчоусы или грибы.)

# Внимание: строки комментария тоже будут переданы команде 'wall' как часть текста.

zzz23EndOfMessagezzz23

# Возможно, более эффективно это может быть сделано так:

# wall <message-file

# Однако, встроенный документ помогает сэкономить ваши силы и время.

exit 0

Пример 17-3. Вывод многострочных сообщений с помощью cat

#!/bin/bash

# Команда 'echo' прекрасно справляется с выводом однострочных сообщений,

# но иногда необходимо вывести несколько строк.

# Команда 'cat' и встроенный документ помогут вам в этом.

cat <<End-of-message

-------------------------------------

Это первая строка сообщения.

Это вторая строка сообщения.

Это третья строка сообщения.

Это четвертая строка сообщения.

Это последняя строка сообщения.

-------------------------------------

End-of-message

exit 0

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

# Команда "exit 0", выше, не позволить исполнить нижележащие строки.

# S.C. отмечает, что следующий код работает точно так же.

echo "-------------------------------------

Это первая строка сообщения.

Это вторая строка сообщения.

Это третья строка сообщения.

Это четвертая строка сообщения.

Это последняя строка сообщения.

-------------------------------------"

# Однако, в этом случае, двойные кавычки в теле сообщения, должны экранироваться.

Если строка-ограничитель встроенного документа начинается с символа - (<<-LimitString), то это приводит к подавлению вывода символов табуляции (но не пробелов). Это может оказаться полезным при форматировании текста сценария для большей удобочитаемости.

Пример 17-4. Вывод многострочных сообщений с подавлением символов табуляции

#!/bin/bash

# То же, что и предыдущий сценарий, но...

# Символ "-", начинающий строку-ограничитель встроенного документа: <<-

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

# но не пробелов.

cat <<-ENDOFMESSAGE

Это первая строка сообщения.

Это вторая строка сообщения.

Это третья строка сообщения.

Это четвертая строка сообщения.

Это последняя строка сообщения.

ENDOFMESSAGE

# Текст, выводимый сценарием, будет смещен влево.

# Ведущие символы табуляции не будут выводиться.

# Вышеприведенные 5 строк текста "сообщения" начинаются с табуляции, а не с пробелов.

exit 0

Встроенные документы поддерживают подстановку команд и параметров. Что позволяет передавать различные параметры в тело встроенного документа.

Пример 17-5. Встроенные документы и подстановка параметров

#!/bin/bash

# Вывод встроенного документа командой 'cat', с использованием подстановки параметров.

# Попробуйте запустить сценарий без аргументов, ./scriptname

# Попробуйте запустить сценарий с одним аргументом, ./scriptname Mortimer

# Попробуйте запустить сценарий с одним аргументом, из двух слов, в кавычках,

# ./scriptname "Mortimer Jones"

CMDLINEPARAM=1 # Минимальное число аргументов командной строки.

if [ $# -ge $CMDLINEPARAM ]

then

NAME=$1 # Если аргументов больше одного,

# то рассматривается только первый.

else

NAME="John Doe" # По-умолчанию, если сценарий запущен без аргументов.

fi

RESPONDENT="автора этого сценария"

cat <<Endofmessage

Привет, $NAME!

Примите поздравления от $RESPONDENT.

# Этот комментарий тоже выводится (почему?).

Endofmessage

# Обратите внимание на то, что пустые строки тоже выводятся.

exit 0

Заключая строку-ограничитель в кавычки или экранируя ее, можно запретить подстановку параметров в теле встроенного документа.

Пример 17-6. Отключение подстановки параметров

#!/bin/bash

# Вывод встроенного документа командой 'cat', с запретом подстановки параметров.

NAME="John Doe"

RESPONDENT="автора этого сценария"

cat <<'Endofmessage'

Привет, $NAME.

Примите поздравления от $RESPONDENT.

Endofmessage

# Подстановка параметров не производится, если строка ограничитель

# заключена в кавычки или экранирована.

# Тот же эффект дают:

# cat <<"Endofmessage"

# cat <<Endofmessage

exit 0

Еще один пример сценария, содержащего встроенный документ и подстановку параметров в его теле.

Пример 17-7. Передача пары файлов во входящий каталог на "Sunsite"

#!/bin/bash

# upload.sh

# Передача пары файлов (Filename.lsm, Filename.tar.gz)

# на Sunsite (ibiblio.org).

E_ARGERROR=65

if [ -z "$1" ]

then

echo "Порядок использования: `basename $0` filename"

exit $E_ARGERROR

fi

Filename=`basename $1` # Отсечь имя файла от пути к нему.

Server="ibiblio.org"

Directory="/incoming/Linux"

# Вообще, эти строки должны бы не "зашиваться" жестко в сценарий,

# а приниматься в виде аргумента из командной строки.

Password="your.e-mail.address" # Измените на свой.

ftp -n $Server <<End-Of-Session

# Ключ -n запрещает автоматическую регистрацию (auto-logon)

user anonymous "$Password"

binary

bell # "Звякнуть" после передачи каждого файла

cd $Directory

put "$Filename.lsm"

put "$Filename.tar.gz"

bye

End-Of-Session

exit 0

Встроенные документы могут передаваться на вход функции, находящейся в том же сценарии.

Пример 17-8. Встроенные документы и функции

#!/bin/bash

# here-function.sh

GetPersonalData ()

{

read firstname

read lastname

read address

read city

read state

read zipcode

} # Это немного напоминает интерактивную функцию, но...

# Передать ввод в функцию.

GetPersonalData <<RECORD001

Bozo

Bozeman

2726 Nondescript Dr.

Baltimore

MD

21226

RECORD001

echo

echo "$firstname $lastname"

echo "$address"

echo "$city, $state $zipcode"

echo

exit 0

Встроенный документ можно передать "пустой команде" :. Такая конструкция, фактически, создает "анонимный" встроенный документ.

Пример 17-9. "Анонимный" Встроенный Документ

#!/bin/bash

: <<TESTVARIABLES

${HOSTNAME?}${USER?}${MAIL?} # Если одна из переменных не определена, то выводится сообщение об ошибке.

TESTVARIABLES

exit 0


Подобную технику можно использовать для создания "блочных комментариев".

Пример 17-10. Блочный комментарий

#!/bin/bash

# commentblock.sh

: << COMMENTBLOCK

echo "Эта строка не будет выведена."

Эта строка комментария не начинается с символа "#".

Это еще одна строка комментария, которая начинается не с символа "#".

&*@!!++=

Эта строка не вызовет ошибки,

поскольку Bash проигнорирует ее.

COMMENTBLOCK

echo "Код завершения "COMMENTBLOCK" = $?." # 0

# Показывает, что ошибок не возникало.

# Такая методика создания блочных комментариев

#+ может использоваться для комментирования блоков кода во время отладки.

# Это экономит силы и время, т.к. не нужно втавлять символ "#" в начале каждой строки,

#+ а затем удалять их.

: << DEBUGXXX

for file in *

do

cat "$file"

done

DEBUGXXX

exit 0


Еще одно остроумное применение встроенных документов -- встроенная справка к сценарию.

Пример 17-11. Встроенная справка к сценарию

#!/bin/bash

# self-document.sh: сценарий со встроенной справкой

# Модификация сценария "colm.sh".

DOC_REQUEST=70

if [ "$1" = "-h" -o "$1" = "--help" ] # Request help.

then

echo; echo "Порядок использования: $0 [directory-name]"; echo

sed --silent -e '/DOCUMENTATIONXX$/,/^DOCUMENTATION/p' "$0" |

sed -e '/DOCUMENTATIONXX/d'; exit $DOC_REQUEST; fi

: << DOCUMENTATIONXX

Сценарий выводит сведения о заданном каталоге в виде таблице.

-------------------------------------------------------------

Сценарию необходимо передать имя каталога. Если каталог не

указан или он недоступен для чтения, то выводятся сведения

о текущем каталоге.

DOCUMENTATIONXX

if [ -z "$1" -o ! -r "$1" ]

then

directory=.

else

directory="$1"

fi

echo "Сведения о каталоге "$directory":"; echo

(printf "PERMISSIONS LINKS OWNER GROUP SIZE MONTH DAY HH:MM PROG-NAMEn"

; ls -l "$directory" | sed 1d) | column -t

exit 0


Для встроенных документов, во время исполнения, создаются временные файлы, но эти файлы удаляются после открытия и недоступны для других процессов.

bash$ bash -c 'lsof -a -p $$ -d0' << EOF

> EOF

lsof 1213 bozo 0r REG 3,5 0 30386 /tmp/t1213-0-sh (deleted)


Некоторые утилиты не могут работать внутри встроенных документов.

Если какая либо задача не может быть решена с помощью "встроенного документа", то вам следует попробовать язык сценариев expect, который приспособлен для передачи параметров на вход интерактивных программ.

Оглавление книги


Генерация: 1.160. Запросов К БД/Cache: 3 / 0
поделиться
Вверх Вниз