Наши партнеры








Книги по Linux (с отзывами читателей)

Библиотека сайта rus-linux.net

На главную -> MyLDP -> Электронные книги по ОС Linux
Руководство по Bash для начинающих
Назад Глава 7: Условные инструкции Вперед

Знакомимся с инструкцией if

Общие положения

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

Самый компактный синтаксис команды if следующий:

if TEST-COMMANDS; then CONSEQUENT-COMMANDS; fi

Выполняется список команд TEST-COMMAND и если они вернут код возврата, равный нулю, будет выполняться список команд CONSEQUENT-COMMANDS. Кодом возврата является код возврата последней выполненной команды, либо ноль, если нет условия, проверяемого на значение истина.

В TEST-COMMAND часто присутствуют сравнения чисел или строк, но также может использоваться любая команда, которая возвращает нулевой код возврата в случае успеха, либо некоторый другой код в случае неудачи. Для проверки состояния файла часто используются унарные выражения. Если аргумент FILE одного из первичных выражений имеет вид /dev/fd/N, то проверяется дескриптор файла "N". При выполнении проверок можно также использовать stdin, stdout и stderr и дескрипторы, соответствующие эти файлам.

Выражения, используемые в инструкции if

В таблице, приведенной ниже, перечисляются так называемые "первичные выражения", из которых состоит команда или список команд TEST-COMMAND. Эти первичные выражения помещаются внутрь квадратных скобок, которые обозначают проверку в условном выражении.

Таблица 7.1. Первичные выражения

Первичное выражениеЗначение

[ -a FILE ]

Истина, если FILE существует.

[ -b FILE ]

Истина, если FILE существует и является блочным файлом.

[ -c FILE ]

Истина, если FILE существует и является строковым файлом.

[ -d FILE ]

Истина, если FILE существует и является директорием.

[ -e FILE ]

Истина, если FILE существует.

[ -f FILE ]

Истина, если FILE существует и является обычным файлом.

[ -g FILE ]

Истина, если FILE существует и у него установлен бит SGID.

[ -h FILE ]

Истина, если FILE существует и является символической ссылкой.

[ -k FILE ]

Истина, если FILE существует и у него установлен промежуточный бит округления.

[ -p FILE ]

Истина, если FILE существует и является именованным конвейером (FIFO).

[ -r FILE ]

Истина, если FILE существует и доступен для чтения.

[ -s FILE ]

Истина, если FILE существует и его размер больше нуля.

[ -t FD ]

Истина, если дескриптор файла FD открыт и ссылается на терминал.

[ -u FILE ]

Истина, если FILE существует и у него установлен бит SUID (установлен идентификатор пользователя ID)

[ -w FILE ]

Истина, если FILE существует и доступен для записи.

[ -x FILE ]

Истина, если FILE существует и является исполняемым.

[ -O FILE ]

Истина, если FILE существует и его владельцем является действующий пользователь.

[ -G FILE ]

Истина, если FILE существует и его владелец принадлежит к действующей группе.

[ -L FILE ]

Истина, если FILE существует и является символической ссылкой.

[ -N FILE ]

Истина, если FILE существует и был модифицирован после последнего чтения.

[ -S FILE ]

Истина, если FILE существует и является сокетом.

[ FILE1 -nt FILE2 ]

Истина, если FILE1 был изменен раньше, чем FILE2, либо если FILE1 существует, а FILE2 не существует.

[ FILE1 -ot FILE2 ]

Истина, если FILE1 изменен позже, чем FILE2, либо если FILE2 существует, а FILE1 не существует.

[ FILE1 -ef FILE2 ]

Истина, если FILE1 и FILE2 ссылаются на одно и то же устройство или на одинаковые номера инодов.

[ -o OPTIONNAME ]

Истина, если установлен параметр командной оболочки "OPTIONNAME".

[ -z STRING ]

Истина, если длина строки "STRING" равна нулю.

[ -n STRING ] или [ STRING ]

Истина, если длина строки "STRING" ненулевая.

[ STRING1 == STRING2 ]

Истина, если строки равны. Для более строгого соответствия POSIX вместо "==" можно использовать "=".

[ STRING1 != STRING2 ]

Истина, если строки не равны

[ STRING1 < STRING2 ]

Истина, если в текущей локали при лексикографической сортировке "STRING1" оказывается перед "STRING2".

[ STRING1 > STRING2 ]

Истина, если в текущей локали при лексикографической сортировке "STRING1" оказывается после "STRING2".

[ ARG1 OP ARG2 ]

"OP" — один из операторов -eq, -ne, -lt, -le, -gt или -ge. Эти арифметические двоичные операторы возвращают значение истина, если операнд "ARG1" соответственно равен, не равен, меньше, меньше или равен, больше или больше или равен операнду "ARG2". "ARG1" и "ARG2" являются целыми числами.

Выражения можно объединять с помощью следующих операторов, перечисляемых в порядке уменьшения их приоритета:

Таблица 7.2. Объединение выражений

ОперацияДействие

[ ! EXPR ]

Истина, если EXPR ложно.

[ ( EXPR ) ]

Возвращает значение EXPR. Используется для изменения нормального предшествования операторов.

[ EXPR1 -a EXPR2 ]

Истина, если оба EXPR1 и EXPR2 являются истинными.

[ EXPR1 -o EXPR2 ]

Истина, если либо EXPR1, либо EXPR2 истинно.

Оценка значений в условных выражениях осуществляется с помощью встроенной команды [ (или test); при этом используется набор правил, учитывающий число аргументов. Более подробную информацию по этой теме можно найти в документации Bash. Точно также, как if должно закрываться fi, после того, как условия будут перечислены, открывающая квадратная скобка должны быть закрыта закрывающей квадратной скобкой.

Команды, идущие за инструкцией then

В списке CONSEQUENT-COMMANDS, которые идут после инструкции then, может присутствовать любая допустимая команда UNIX, любая исполняемая программа, любой исполняемый скрипт командной оболочки или любая инструкция командной оболочки за исключением закрывающей инструкции fi. Важно помнить, что then и fi считаются в командной оболочке различными инструкциями. Поэтому, когда они набираются в командной строке, их надо разделять точкой с запятой.

В скрипте разные части инструкции if, как правило, хорошо разделены. Ниже приводится несколько простых примеров.

Проверка файлов

В первом примере проверяется существование файла:

anny ~> cat msgcheck.sh
#!/bin/bash

echo "This scripts checks the existence of the messages file."
echo "Checking..."
if [ -f /var/log/messages ]
  then
    echo "/var/log/messages exists."
fi
echo
echo "...done."

anny ~> ./msgcheck.sh
This scripts checks the existence of the messages file.
Checking...
/var/log/messages exists.

...done.

Проверка параметров командной оболочки

Для добавления в ваш конфигурационный файл Bash:

# These lines will print a message if the noclobber option is set:

if [ -o noclobber ]
  then
        echo "Your files are protected against accidental overwriting using redirection."
fi

Среда исполнения

Приведенный выше пример будет работать, если ввести его в командной строке:

anny ~> if [ -o noclobber ] ; then echo ; echo "your files are protected
against overwriting." ; echo ; fi

your files are protected against overwriting.

anny ~>
Однако, если вы проверяете условия, которые зависят от настройки окружающей среды, вы можете получить другие результаты, когда вы ту же самую команду добавляете в скрипт, т. к. скрипт открывает новую оболочку, в которой интересующие вас переменных и параметры могут автоматически не устанавливаться.

Простые примеры использования if

Проверка кода возврата

В переменной ? хранится код возврата предыдущей команды (самого последнего процесса, завершенного в фоновом режиме).

В следующем примере показывается простая проверка:

anny ~> if [ $? -eq 0 ]
More input> then echo 'That was a good job!'
More input> fi
That was a good job!

anny ~>

В следующем примере демонстрируется, что в TEST-COMMANDS может быть любая команда UNIX, которая возвращает код возврата, и что инструкция if в свою очередь вернет код возврата, который равен нулю:

anny ~> if ! grep $USER /etc/passwd
More input> then echo "your user account is not managed locally"; fi
your user account is not managed locally

anny > echo $?
0

anny >

Тот же самый результат можно получить следующим образом:

anny > grep $USER /etc/passwd

anny > if [ $? -ne 0 ] ; then echo "not a local account" ; fi
not a local account

anny >

Сравнение чисел

В приведенных ниже примерах используется сравнение чисел:

anny > num=`wc -l work.txt`

anny > echo $num
201

anny > if [ "$num" -gt "150" ]
More input> then echo ; echo "you've worked hard enough for today."
More input> echo ; fi

you've worked hard enough for today.


anny >

Этот скрипт выполняется с помощью cron каждое воскресенье. Если номер недели четный, скрипт напомнит вам почистить мусорную корзину:

#!/bin/bash

# Calculate the week number using the date command:

WEEKOFFSET=$[ $(date +"%V") % 2 ]

# Test if we have a remainder.  If not, this is an even week so send a message.
# Else, do nothing.

if [ $WEEKOFFSET -eq "0" ]; then
  echo "Sunday evening, put out the garbage cans." | mail -s "Garbage cans out" your@your_domain.org
fi

Сравнения строк

Пример сравнение строк, в котором проверяется идентификатор пользователя:

if [ "$(whoami)" != 'root' ]; then
        echo "You have no permission to run $0 as non-root user."
        exit 1;
fi

В Bash вы можете сократить этот вид конструкции. Компактный эквивалент приведенной выше проверки будет следующим:

[ "$(whoami)" != 'root' ] && ( echo you are using a non-privileged account; exit 1 )

Точно также, как выражение "&&" указывает, что делать, если проверка возвратит истинное значение, выражение "||" указывает, что делать, если проверка возвратит ложное значение.

В сравнениях также можно использовать регулярные выражения:

anny > gender="female"

anny > if [[ "$gender" == f* ]]
More input> then echo "Pleasure to meet you, Madame."; fi
Pleasure to meet you, Madame.

anny >
Практическое программирование
Большинство программистов предпочитают использовать встроенную команду test, которая эквивалентна квадратным скобкам, используемым при сравнении, например:
test "$(whoami)" != 'root' && (echo you are using a non-privileged account; exit 1)
 
Не использовать exit?

Если вы в подоболочке вызываете команду exit, она не передаст значение переменных в родительскую оболочку. Если вы не хотите, чтобы при этом Bash создавал еще одну подоболочку, используйте "{" и "}" вместо "(" и ")".

Смотрите документацию по Bash для получения дополнительной информации по использованию шаблонов с конструкциями "(( EXPRESSION ))" и "[[ EXPRESSION ]]".


Предыдущий раздел: Оглавление Следующий раздел:
Подводим итоги главы 6   Расширенные варианты использования конструкции if