Пример 9-1. $IFS и пробельные символы
Пример 9-1. $IFS и пробельные символы
#!/bin/bash
# При использовании $IFS, пробельные символы обрабатываются иначе, чем все остальные.
output_args_one_per_line()
{
for arg
do echo "[$arg]"
done
}
echo; echo "IFS=" ""
echo "-------"
IFS=" "
var=" a b c "
output_args_one_per_line $var # output_args_one_per_line `echo " a b c "`
#
# [a]
# [b]
# [c]
echo; echo "IFS=:"
echo "-----"
IFS=:
var=":a::b:c:::" # То же самое, только пробелы зменены символом ":".
output_args_one_per_line $var
#
# []
# [a]
# []
# [b]
# [c]
# []
# []
# []
# То же самое происходит и с разделителем полей "FS" в awk.
# Спасибо Stephane Chazelas.
echo
exit 0
(Спасибо S. C., за разъяснения и примеры.)
$LC_COLLATE
Чаще всего устанавливается в .bashrc или /etc/profile, эта переменная задает порядок сортировки символов, в операциях подстановки имен файлов и в поиске по шаблону. При неверной настройке переменной LC_COLLATE можно получить весьма неожиданные результаты.
Начиная с версии 2.05, Bash, в операциях подстановки имен файлов, не делает различий между символами верхнего и нижнего регистров, в диапазонах символов в квадратных скобках. Например,, ls [A-M]* выведет как File1.txt, так и file1.txt. Возврат к общепринятому стандарту поведения шаблонов в квадратных скобках выполняется установкой переменной LC_COLLATE в значение C командой export LC_COLLATE=C в файле /etc/profile и/или ~/.bashrc.
$LC_CTYPE
Эта внутренняя переменная определяет кодировку символов. Используется в операциях подстановки и поиске по шаблону.
$LINENO
Номер строки исполняемого сценария. Эта переменная имеет смысл только внутри исполняемого сценария и чаще всего применяется в отладочных целях.
# *** BEGIN DEBUG BLOCK ***
last_cmd_arg=$_ # Запомнить.
echo "Строка $LINENO: переменная "v1" = $v1"
echo "Последний аргумент командной строки = $last_cmd_arg"
# *** END DEBUG BLOCK ***
$MACHTYPE
аппаратная архитектура
Идентификатор аппаратной архитектуры.
bash$ echo $MACHTYPE
i686
$OLDPWD
прежний рабочий каталог ("OLD-Print-Working-Directory")
$OSTYPE
тип операционной системы
bash$ echo $OSTYPE
linux
$PATH
путь поиска, как правило включает в себя каталоги /usr/bin/, /usr/X11R6/bin/, /usr/local/bin, и т.д.
Когда командный интерпретатор получает команду, то он автоматически пытается отыскать соответствующий исполняемый файл в указанном списке каталогов (в переменной $PATH). Каталоги, в указанном списке, должны отделяться друг от друга двоеточиями. Обычно, переменная $PATH инициализируется в /etc/profile и/или в ~/.bashrc (см. Глава 26).
bash$ echo $PATH
/bin:/usr/bin:/usr/local/bin:/usr/X11R6/bin:/sbin:/usr/sbin
Инструкция PATH=${PATH}:/opt/bin добавляет каталог /opt/bin в конец текущего пути поиска. Иногда может оказаться целесообразным, внутри сценария, временно добавить какой-либо каталог к пути поиска. По завершении работы скрипта, эти изменения будут утеряны (вспомните о том, что невозможно изменить переменные окружения вызывающего процесса).
Текущий "рабочий каталог", ./, обычно не включается в $PATH из соображений безопасности.
$PIPESTATUS
Код возврата канала (конвейера). Интересно, что это не то же самое, что код возврата последней исполненной команды.
bash$ echo $PIPESTATUS
0
bash$ ls -al | bogus_command
bash: bogus_command: command not found
bash$ echo $PIPESTATUS
141
bash$ ls -al | bogus_command
bash: bogus_command: command not found
bash$ echo $?
127
Переменная $PIPESTATUS может давать неверные значения при вызове из командной строки.
tcsh% bash
bash$ who | grep nobody | sort
bash$ echo ${PIPESTATUS[*]}
0
Если поместить эти строки в сценарий и исполнить его, то будут выведены верные значения 0 1 0.
Спасибо Wayne Pollock за замечания и предоставленный пример.
$PPID
Переменная $PPID хранит PID (идентификатор) родительского процесса.[ 19 ]
Сравните с командой pidof.
$PS1
prompt, приглашение командной строки.
$PS2
Вторичное приглашение командной строки, выводится тогда, когда от пользователя ожидается дополнительный ввод. Отображается как ">".
$PS3
Третичное приглашение (prompt), выводится тогда, когда пользователь должен сделать выбор в операторе select (см. Пример 10-29).
$PS4
Приглашение (prompt) четвертого уровня, выводится в начале каждой строки вывода тогда, когда сценарий вызывается с ключом -x. Отображается как "+".
$PWD
рабочий (текущий) каталог
Аналог встроенной команды pwd.
#!/bin/bash
E_WRONG_DIRECTORY=73
clear # Очистка экрана.
TargetDirectory=/home/bozo/projects/GreatAmericanNovel
cd $TargetDirectory
echo "Удаление файлов в каталоге $TargetDirectory."
if [ "$PWD" != "$TargetDirectory" ]
then # Защита от случайного удаления файлов не в том каталоге.
echo "Неверный каталог!"
echo "Переменная $PWD указывает на другой каталог!"
exit $E_WRONG_DIRECTORY
fi
rm -rf *
rm .[A-Za-z0-9]* # удалить "скрытые" файлы (начинающиеся с ".")
# rm -f .[^.]* ..?* удалить файлы, чьи имена начинаются с нескольких точек.
# (shopt -s dotglob; rm -f *) тоже работает верно.
# Спасибо S.C. за замечание.
# Имена файлов могут содержать любые символы из диапазона 0-255, за исключением "/".
# Оставляю вопрос удаления файлов с "необычными" символами для самостоятельного изучения.
# Здесь можно вставить дополнительные действия, по мере необходимости.
echo
echo "Конец."
echo "Файлы, из каталога $TargetDirectory, удалены."
echo
exit 0
$REPLY
переменная по-умолчанию, куда записывается ввод пользователя, выполненный с помощью команды read если явно не задана другая переменная. Так же может использоваться в операторе select, для построения меню выбора.
#!/bin/bash
echo
echo -n "Ваше любимое растение? "
read
echo "Ваше любимое растение: $REPLY."
# REPLY хранит последнее значение, прочитанное командой "read" тогда, и только тогда
#+ когда команде "read" не передается имя переменной.
echo
echo -n "Ваш любимый фрукт? "
read fruit
echo "Ваш любимый фрукт $fruit."
echo "но..."
echo "Значение переменной $REPLY осталось равным $REPLY."
# Переменная $REPLY не была перезаписана потому, что
# следующей команде "read", в качестве аргумента была передана переменная $fruit
echo
exit 0
$SECONDS
Время работы сценария в секундах.
#!/bin/bash
# Автор: Mendel Cooper
# Дополнен переводчиком.
#
TIME_LIMIT=10
INTERVAL=1
echo
echo "Для прерывания работы сценария, ранее чем через $TIME_LIMIT секунд, нажмите Control-C."
echo
while [ "$SECONDS" -le "$TIME_LIMIT" ]
do
# Оригинальный вариант сценария содержал следующие строки
# if [ "$SECONDS" -eq 1 ]
# then
# units=second
# else
# units=seconds
# fi
#
# Однако, из-за того, что в русском языке для описания множественного числа
# существует большее число вариантов, чем в английском,
# переводчик позволил себе смелость несколько подправить сценарий
# (прошу ногами не бить! ;-) )
# === НАЧАЛО БЛОКА ИЗМЕНЕНИЙ, ВНЕСЕННЫХ ПЕРЕВОДЧИКОМ ===
let "last_two_sym = $SECONDS - $SECONDS / 100 * 100" # десятки и единицы
if [ "$last_two_sym" -ge 11 -a "$last_two_sym" -le 19 ]
then
units="секунд" # для чисел, которые заканчиваются на "...надцать"
else
let "last_sym = $last_two_sym - $last_two_sym / 10 * 10" # единицы
case "$last_sym" in
"1" )
units="секунду" # для чисел, заканчивающихся на 1
;;
"2" | "3" | "4" )
units="секунды" # для чисел, заканчивающихся на 2, 3 и 4
;;
* )
units="секунд" # для всех остальных (0, 5, 6, 7, 8, 9)
;;
esac
fi
# === КОНЕЦ БЛОКА ИЗМЕНЕНИЙ, ВНЕСЕННЫХ ПЕРЕВОДЧИКОМ ===
echo "Сценарий отработал $SECONDS $units."
# В случае перегруженности системы, скрипт может перескакивать через отдельные
#+ значения счетчика
sleep $INTERVAL
done
echo -e "a" # Сигнал!
exit 0
$SHELLOPTS
список допустимых опций интерпретатора shell. Переменная доступна только для чтения.
bash$ echo $SHELLOPTS
braceexpand:hashall:histexpand:monitor:history:interactive-comments:emacs
$SHLVL
Уровень вложенности shell. Если в командной строке
echo $SHLVL
дает 1, то в сценарии значение этой переменной будет больше на 1, т.е. 2.
$TMOUT
Если переменная окружения $TMOUT содержит ненулевое значение, то интерпретатор будет ожидать ввод не более чем заданное число секунд, что, в первичном приглашении (см. описание PS1 выше), может привести к автоматическому завершению сеанса работы.
К сожалению это возможно только во время ожидания ввода с консоли или в окне терминала. А как было бы здорово, если бы можно было использовать эту внутреннюю переменную, скажем в комбинации с командой read! Но в данном контексте эта переменная абсолютно не применима и потому фактически бесполезна в сценариях. (Есть сведения о том, что в ksh время ожидания ввода командой read можно ограничить.)
Организация ограничения времени ожидания ввода от пользователя в сценариях возможна, но это требут довольно сложных махинаций. Как один из вариантов, можно предложить организовать прерывание цикла ожидания по сигналу. Но это потребует написание функции обработки сигналов командой trap (см. Пример 29-5).