Мендель Купер - Искусство программирования на языке сценариев командной оболочки
Переменные $* и [email protected], в отдельных случаях, могут содержать противоречивую информацию! Это зависит от содержимого переменной $IFS.
Пример 9-7. Противоречия в переменных $* и [email protected]
#!/bin/bash
# Демонстрация противоречивости содержимого внутренних переменных "$*" и " [email protected]",
#+ которая проявляется при изменении порядка заключения параметров в кавычки.
# Демонстрация противоречивости, проявляющейся при изменении
#+ содержимого переменной IFS.
set -- "Первый один" "второй" "третий:один" "" "Пятый: :один"
# Установка аргументов $1, $2, и т.д.
echo
echo 'IFS по-умолчанию, переменная "$*"'
c=0
for i in "$*" # в кавычках
do echo "$((c+=1)): [$i]" # Эта строка остается без изменений во всех циклах.
# Вывод аргументов.
done
echo ---
echo 'IFS по-умолчанию, переменная $*'
c=0
for i in $* # без кавычек
do echo "$((c+=1)): [$i]"
done
echo ---
echo 'IFS по-умолчанию, переменная " [email protected]"'
c=0
for i in " [email protected]"
do echo "$((c+=1)): [$i]"
done
echo ---
echo 'IFS по-умолчанию, переменная [email protected]'
c=0
for i in [email protected]
do echo "$((c+=1)): [$i]"
done
echo ---
IFS=:
echo 'IFS=":", переменная "$*"'
c=0
for i in "$*"
do echo "$((c+=1)): [$i]"
done
echo ---
echo 'IFS=":", переменная $*'
c=0
for i in $*
do echo "$((c+=1)): [$i]"
done
echo ---
var=$*
echo 'IFS=":", переменная "$var" (var=$*)'
c=0
for i in "$var"
do echo "$((c+=1)): [$i]"
done
echo ---
echo 'IFS=":", переменная $var (var=$*)'
c=0
for i in $var
do echo "$((c+=1)): [$i]"
done
echo ---
var="$*"
echo 'IFS=":", переменная $var (var="$*")'
c=0
for i in $var
do echo "$((c+=1)): [$i]"
done
echo ---
echo 'IFS=":", переменная "$var" (var="$*")'
c=0
for i in "$var"
do echo "$((c+=1)): [$i]"
done
echo ---
echo 'IFS=":", переменная " [email protected]"'
c=0
for i in " [email protected]"
do echo "$((c+=1)): [$i]"
done
echo ---
echo 'IFS=":", переменная [email protected]'
c=0
for i in [email protected]
do echo "$((c+=1)): [$i]"
done
echo ---
[email protected]
echo 'IFS=":", переменная $var ( [email protected])'
c=0
for i in $var
do echo "$((c+=1)): [$i]"
done
echo ---
echo 'IFS=":", переменная "$var" ( [email protected])'
c=0
for i in "$var"
do echo "$((c+=1)): [$i]"
done
echo ---
var=" [email protected]"
echo 'IFS=":", переменная "$var" (var=" [email protected]")'
c=0
for i in "$var"
do echo "$((c+=1)): [$i]"
done
echo ---
echo 'IFS=":", переменная $var (var=" [email protected]")'
c=0
for i in $var
do echo "$((c+=1)): [$i]"
done
echo
# Попробуйте запустить этот сценарий под ksh или zsh -y.
exit 0
# Это сценарий написан Stephane Chazelas,
# Незначительные изменения внесены автором документа.
Различия между [email protected] и $* наблюдаются только тогда, когда они помещаются в двойные кавычки.
Пример 9-8. Содержимое $* и [email protected], когда переменная $IFS -- пуста
#!/bin/bash
# Если переменная $IFS инициализирована "пустым" значением,
# то "$*" и " [email protected]" содержат аргументы не в том виде, в каком ожидается.
mecho () # Вывод аргументов.
{
echo "$1,$2,$3";
}
IFS="" # Инициализация "пустым" значением.
set a b c # Установка аргументов.
mecho "$*" # abc,,
mecho $* # a,b,c
mecho [email protected] # a,b,c
mecho " [email protected]" # a,b,c
# Поведение переменных $* и [email protected], при "пустой" $IFS, зависит
# от версии командной оболочки, Bash или sh.
# Поэтому, было бы неразумным пользоваться этой "фичей" в своих сценариях.
# Спасибо S.C.
exit 0
Прочие специальные переменные
$-
Список флагов, переданных сценарию (командой set). См. Пример 11-13.
Эта конструкция изначально была введена в ksh, откуда перекочевала в Bash и, похоже, работает в Bash не совсем надежно. Единственное возможное применение -- проверка - запущен ли сценарий в интерактивном режиме.
$!
PID последнего, запущенного в фоне, процесса
LOG=$0.log
COMMAND1="sleep 100"
echo "Запись в лог всех PID фоновых процессов, запущенных из сценария: $0" >> "$LOG"
# Таким образом возможен мониторинг и удаление процессов по мере необходимости.
echo >> "$LOG"
# Команды записи в лог.
echo -n "PID of "$COMMAND1": " >> "$LOG"
${COMMAND1} &
echo $! >> "$LOG"
# PID процесса "sleep 100": 1506
# Спасибо Jacques Lederer за предложенный пример.
$_
Специальная переменная, содержит последний аргумент предыдущей команды.
Пример 9-9. Переменная "подчеркивание"
#!/bin/bash
echo $_ # /bin/bash
# Для запуска сценария был вызван /bin/bash.
du >/dev/null # Подавление вывода.
echo $_ # du
ls -al >/dev/null # Подавление вывода.
echo $_ # -al (последний аргумент)
:
echo $_ # :
$?
Код возврата команды, функции или скрипта (см. Пример 22-3)
$$
PID самого процесса-сценария. Переменная $$ часто используется при генерации "уникальных" имен для временных файлов (см. Пример A-14, Пример 29-6, Пример 12-23 и Пример 11-23). Обычно это проще чем вызов mktemp.
9.2. Работа со строками
Bash поддерживает на удивление большое количество операций над строками. К сожалению, этот раздел Bash испытывает недостаток унификации. Одни операции являются подмножеством операций подстановки параметров, а другие -- совпадают с функциональностью команды UNIX -- expr. Это приводит к противоречиям в синтаксисе команд и перекрытию функциональных возможностей, не говоря уже о возникающей путанице.
Длина строки
${#string}
expr length $string
expr "$string" : '.*'
stringZ=abcABC123ABCabc
echo ${#stringZ} # 15
echo `expr length $stringZ` # 15
echo `expr "$stringZ" : '.*'` # 15
Пример 9-10. Вставка пустых строк между параграфами в текстовом файле
#!/bin/bash
# paragraph-space.sh
# Вставка пустых строк между параграфами в текстовом файле.
# Порядок использования: $0 <FILENAME
MINLEN=45 # Возможно потребуется изменить это значение.
# Строки, содержащие количество символов меньшее, чем $MINLEN
#+ принимаются за последнюю строку параграфа.
while read line # Построчное чтение файла от начала до конца...
do
echo "$line" # Вывод строки.
len=${#line}
if [ "$len" -lt "$MINLEN" ]
then echo # Добавление пустой строки после последней строки параграфа.
fi
done
exit 0
Длина подстроки в строке (подсчет совпадающих символов ведется с начала строки)
expr match "$string" '$substring'
где $substring -- регулярное выражение.
expr "$string" : '$substring'
где $substring -- регулярное выражение.
stringZ=abcABC123ABCabc
# |------|
echo `expr match "$stringZ" 'abc[A-Z]*.2'` # 8
echo `expr "$stringZ" : 'abc[A-Z]*.2'` # 8
Index
expr index $string $substring
Номер позиции первого совпадения в $string c первым символом в $substring.
stringZ=abcABC123ABCabc
echo `expr index "$stringZ" C12` # 6
# позиция символа C.