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

Глава 31. Широко распространенные ошибки

Turandot: Gli enigmi sono tre, la morte una!

Caleph: No, no! Gli enigmi sono tre, una la vita!

Puccini

Использование зарезервированных слов и служебных символов в качестве имен переменных.

case=value0 # Может вызвать проблемы.

23skidoo=value1 # Тоже самое.

# Имена переменных, начинающиеся с цифр, зарезервированы командной оболочкой.

# Если имя переменной начинается с символа подчеркивания: _23skidoo=value1, то это не считается ошибкой.

# Однако... если имя переменной состоит из единственного символа подчеркивания, то это ошибка.

_=25

echo $_ # $_ -- это внутренняя переменная.

xyz((!*=value2 # Вызывает серьезные проблемы.

Использование дефиса, и других зарезервированных символов, в именах переменных.

var-1=23

# Вместо такой записи используйте 'var_1'.

Использование одинаковых имен для переменных и функций. Это делает сценарий трудным для понимания.

do_something ()

{

echo "Эта функция должна что-нибудь сделать с "$1"."

}

do_something=do_something

do_something do_something

# Все это будет работать правильно, но слишком уж запутанно.

Использование лишних пробелов. В отличие от других языков программирования, Bash весьма привередлив по отношению к пробелам.

var1 = 23 # Правильный вариант: 'var1=23'.

# В вышеприведенной строке Bash будет трактовать "var1" как имя команды

# с аргументами "=" и "23".

let c = $a - $b # Правильный вариант: 'let c=$a-$b' или 'let "c = $a - $b"'

if [ $a -le 5] # Правильный вариант: if [ $a -le 5 ]

# if [ "$a" -le 5 ] еще лучше.

# [[ $a -le 5 ]] тоже верно.

Ошибочным является предположение о том, что неинициализированные переменные содержат "ноль". Неинициализированные переменные содержат "пустое" (null) значение, а не ноль.

#!/bin/bash

echo "uninitialized_var = $uninitialized_var"

# uninitialized_var =

Часто программисты путают операторы сравнения = и -eq. Запомните, оператор = используется для сравнения строковых переменных, а -eq -- для сравнения целых чисел.

if [ "$a" = 273 ] # Как вы полагаете? $a -- это целое число или строка?

if [ "$a" -eq 273 ] # Если $a -- целое число.

# Иногда, такого рода ошибка никак себя не проявляет.

# Однако...

a=273.0 # Не целое число.

if [ "$a" = 273 ]

then

echo "Равны."

else

echo "Не равны."

fi # Не равны.

# тоже самое и для a=" 273" и a="0273".

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

if [ "$a" -eq 273.0 ]

then

echo "a = $a'

fi # Исполнение сценария прерывается по ошибке.

# test.sh: [: 273.0: integer expression expected

Ошибки при сравнении целых чисел и строковых значений.

#!/bin/bash

# bad-op.sh

number=1

while [ "$number" < 5 ] # Неверно! должно быть while [ "number" -lt 5 ]

do

echo -n "$number "

let "number += 1"

done

# Этот сценарий генерирует сообщение об ошибке:

# bad-op.sh: 5: No such file or directory

Иногда, в операциях проверки, с использованием квадратных скобок ([ ]), переменные необходимо брать в двойные кавычки. См. Пример 7-6, Пример 16-4 и Пример 9-6.

Иногда сценарий не в состоянии выполнить команду из-за нехватки прав доступа. Если пользователь не сможет запустить команду из командной строки, то эта команда не сможет быть запущена и из сценария. Попробуйте изменить атрибуты команды, возможно вам придется установить бит suid.

Использование символа - в качестве оператора перенаправления (каковым он не является) может приводить к неожиданным результатам.

command1 2> - | command2 # Попытка передать сообщения об ошибках команде command1 через конвейер...

# ...не будет работать.

command1 2>& - | command2 # Так же бессмысленно.

Спасибо S.C.

Использование функциональных особенностей Bash версии 2 или выше, может привести к аварийному завершению сценария, работающему под управлением Bash версии 1.XX.

#!/bin/bash

minimum_version=2

# Поскольку Chet Ramey постоянно развивает Bash,

# вам может потребоваться указать другую минимально допустимую версию $minimum_version=2.XX.

E_BAD_VERSION=80

if [ "$BASH_VERSION" < "$minimum_version" ]

then

echo "Этот сценарий должен исполняться под управлением Bash, версии $minimum или выше."

echo "Настоятельно рекомендуется обновиться."

exit $E_BAD_VERSION

fi

...

Использование специфических особенностей Bash может приводить к аварийному завершению сценария в Bourne shell (#!/bin/sh). Как правило, в Linux дистрибутивах, sh является псевдонимом bash, но это не всегда верно для UNIX-систем вообще.

Сценарий, в котором строки отделяются друг от друга в стиле MS-DOS (rn), будет завершаться аварийно, поскольку комбинация #!/bin/bashrn считается недопустимой. Исправить эту ошибку можно простым удалением символа r из сценария.

#!/bin/bash

echo "Начало"

unix2dos $0 # Сценарий переводит символы перевода строки в формат DOS.

chmod 755 $0 # Восстановление прав на запуск.

# Команда 'unix2dos' удалит право на запуск из атрибутов файла.

./$0 # Попытка запустить себя самого.

# Но это не сработает из-за того, что теперь строки отделяются

# друг от друга в стиле DOS.

echo "Конец"

exit 0

Сценарий, начинающийся с #!/bin/sh, не может работать в режиме полной совместимости с Bash. Некоторые из специфических функций, присущих Bash, могут оказаться запрещенными к использованию. Сценарий, который требует полного доступа ко всем расширениям, имеющимся в Bash, должен начинаться строкой #!/bin/bash.

Сценарий не может экспортировать переменные родительскому процессу - оболочке. Здесь как в природе, потомок может унаследовать черты родителя, но не наооборот.

WHATEVER=/home/bozo

export WHATEVER

exit 0

bash$ echo $WHATEVER

bash$

Будьте уверены -- при выходе в командную строку переменная $WHATEVER останется неинициализированной.

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

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

Оглавление статьи/книги

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