Bash by example / Bash в примерах: Part 2: More bash programming fundamentals

← →
Английский оригинал Перевод на русский

Сожалеем, но текст оригинала доступен только зарегистрированным пользователям.

Передача аргументов командной строки

Daemon786 24.01.11 в 15:02

0

Для начала, небольшой совет по использованию аргументов командной строки - а потом мы рассмотрим основные состовляющие Баша.

icori 22.01.11 в 08:45

0

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

mslasm 27.01.11 в 19:34

1
+1

В примере, даннов во введении, мы использовали переменную окружения "$1", которая указывает на первый аргумент командной строки. Точно так же, можно использовать "$2", "$3", и т.д. чтобы указать на второй и третий аргумент, данный вашему скрипту. Вот пример:

icori 22.01.11 в 08:50

0

В простой программе из вступительной статьи мы использовали переменную окружения "$1", которая ссылается на первый аргумент командной строки. Аналогично вы можете использовать "$2", "$3" и т.д., чтобы указать на второй и третий аргументы, переданные вашему сценарию. Вот пример:

Daemon786 24.01.11 в 13:46

0

#!/usr/bin/env bash

echo name of script is $0
echo first argument is $1
echo second argument is ${2}
echo seventeenth argument is ${17}
echo number of arguments is $#

Daemon786 21.01.11 в 08:10

0

Пример говорит сам за себя, за исключением трех маленьких деталей. Во-первых, "$0" выведет имя сценария, которое указано при вызове из командной строки, а "$#" укажет количество аргументов переданных сценарию. Использование фигурных скобок является необязательным для однозначных номеров, но необходимо для аргументов выше "$9". Поиграйте с приведенным сценарием, подставляя различные аргументы командной строки, чтобы запомнить как это работает.

Daemon786 24.01.11 в 14:31

0

Иногда удобно обозначить сразу все аргументы командной строки. Для этого используется переменная "$@", которая объединит в себе все параметры командной строки, разделенные пробелами. Мы увидим пример ее использования чуть позже в этой статье, когда будем рассматривать циклы "for".

Daemon786 24.01.11 в 15:01

0

Управляющие конструкции в bash

Daemon786 24.01.11 в 15:50

0

Если вы программировали на процедурных языках, таких как C, Pascal, Python или Perl, то вы хорошо знакомы с такими управляющими конструкциями как операторы "if", циклы "for" и тому подобные. Bash имеет свои собственные версии большинства из этих стандартных конструкций. В следующих разделах я расскажу о нескольких управляющих конструкциях и продемонстрирую их отличия от их аналогов в других известных вам языках программирования. Если вы не имеете опыта программирования, не волнуйтесь. Я включил достаточно информации и примеров, чтобы вы смогли следить за текстом.

Daemon786 24.01.11 в 15:50

0

Любовь к условиям

undeceived 30.01.11 в 16:08

1

Если вам когда-либо приходилось писать код для работы с файлами на С, то вы знаете, что для того, чтобы сравнить даты создания двух файлов требуется приложить значительное количество усилий. Так происходит потому, что в языке С нету встроенных средств для подобных сравнений; и вот приходится делать два вызова stat(), использовать две структуры stat и делать сравнения вручную. Напротив, в bash уже имеются встроенные средства для работы с файлами и, таким образом, проверка "имеется ли доступ на чтение к файлу /tmp/myfile" не сложнее проверки "значение переменной $myvar больше 4?".

undeceived 30.01.11 в 15:57

1

В таблице ниже приведен список наиболее часто используемых операций сравнения в bash. Также в ней вы найдете примеры правильного использования каждой операции.

Приведенные примеры следует размещать непосредственно после "if". Например:

undeceived 30.01.11 в 16:00

1

if [ -z "$myvar" ]
then
echo "myvar is not defined"
fi

Daemon786 21.01.11 в 08:11

0

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

undeceived 30.01.11 в 16:02

1

if [ "$myvar" -eq 3 ]
then
echo "myvar equals 3"
fi

if [ "$myvar" = "3" ]
then
echo "myvar equals 3"
fi

Daemon786 21.01.11 в 08:11

0

Хотя оба примера выше и выполяют одно и то же действие, но разница заключается в том, что в первом используется арифметическая операция сравнения, а во втором - строковая.

undeceived 30.01.11 в 16:08

1

Замечания о сравнении строк.

undeceived 30.01.11 в 16:09

1

В большинстве случаев можно не помещать строковые переменные в двойные кавычки, но это не слишком хорошая практика. Почему? Потому что ваш код будет работать правильно до тех пор, пока в строковой переменной не появится символы пробела или табуляции. В таком случае bash придет в некоторое замешательство. Вот пример хренового сравнения:

undeceived 30.01.11 в 16:12

1

В большинстве случаев можно не помещать строковые переменные в двойные кавычки, но это не слишком хорошая практика. Почему? Потому что ваш код будет работать правильно до тех пор, пока в строковой переменной не появится символы пробела или табуляции. В таком случае bash придет в некоторое замешательство. Вот пример никуда ни годного сравнения:

Daemon786 06.02.11 в 20:30

0

if [ $myvar = "foo bar oni" ]
then
echo "yes"
fi

Daemon786 21.01.11 в 08:12

0

В данном примере, если значение myvar равно "foo" - код будет работать правильно и ничего не напечатает. Однако, если значение myvar равно "foo bar oni" - при исполнении код выдаст ошибку:

undeceived 30.01.11 в 16:13

1

[: too many arguments

Daemon786 21.01.11 в 08:12

0

В данном случае пробелы внутри значения переменной $myvar (значение которой равно "foo bar oni") приведут к тому, что bash не будет знать как сравнивать значения. После того, как bash подставит значение переменной $myvar операция сравнения будет выглядеть так:

undeceived 30.01.11 в 16:16

0

[ foo bar oni = "foo bar oni" ]

Daemon786 21.01.11 в 09:03

0

Так как переменная не была помещена внутри двойных кавычек - bash решит, что вы передали слишком много аргументов внутри квадратных скобок. Эту проблему легко решить поместив переменную в двойные кавычки.

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

Вот как пример с "foo bar oni" должен был быть написан правильно:

undeceived 30.01.11 в 16:18

1

if [ "$myvar" = "foo bar oni" ]
then
echo "yes"
fi

Daemon786 21.01.11 в 09:03

0

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

undeceived 30.01.11 в 16:19

1

Примечание:
Если вы хотите, чтобы bash подставлял значения переменных - помещайте их в двойные, а не одинарные кавычки. Одинарные кавычки запрещают подстановку значения переменных.

undeceived 30.01.11 в 16:21

0

Примечание:
Если вы хотите, чтобы bash подставлял значения переменных - помещайте их в двойные, а не одинарные кавычки. Одинарные кавычки запрещают подстановку значения переменных.

undeceived 30.01.11 в 16:21

0
+2

Циклические конструкции: "for"

Daemon786 21.01.11 в 09:46

0

Итак, мы рассмотрели условные операторы, а теперь пришло время разобраться с конструированием циклов в bash. Начнем мы со стандартного цикла "for".

Вот простой пример:

undeceived 30.01.11 в 16:23

1

#!/usr/bin/env bash

for x in one two three four
do
echo number $x
done

Вывод:
number one
number two
number three
number four

Daemon786 21.01.11 в 09:04

0

Давайте разберемся что тут произошло.

Часть "for x" объявления цикла "for" определила новую переменную (она называется переменной контроля цикла) "$x", которой были успешно присвоены значения "one", "two", "three" и "four". После каждого из присваиваний тело цикла (код, находящийся между "do" ... "done") было выполнено один раз. В теле цикла мы использовали переменную контроля цикла "$x" используя точно такой же синтаксис, как и для любой другой переменной.

Также обратите внимание на то, что цикл "for" после конструкции "in" всегда принимает на вход какой-нибудь список слов. В данном примере мы указали четыре английских слова, но в общем случае список может включать пути к файлам на диске или даже шаблоны (символы подстановки). Взгляните на пример ниже, который демонстрирует то, как можно использовать стандартные шаблоны оболочки:

undeceived 30.01.11 в 16:32

1

#!/usr/bin/env bash

for myfile in /etc/r*
do
if [ -d "$myfile" ]
then
echo "$myfile (dir)"
else
echo "$myfile"
fi
done

вывод:

/etc/rc.d (dir)
/etc/resolv.conf
/etc/resolv.conf~
/etc/rpc

Daemon786 21.01.11 в 09:05

0

Приведенный выше код перебирает все файлы в каталоге /etc, которые начинаются с "r". Для того, чтобы это сделать перед выполнением цикла bash сначала заменил "/etc/r*" на соответствующие этому шаблону строку /etc/rc.d /etc/resolv.conf /etc/resolv.conf~ /etc/rpc.

Внутри тела цикла условие "-d" было использовано выяснения является ли путь - директорией. И если является - к строке вывода добавлялась строка "(dir)".

undeceived 30.01.11 в 16:41

1

Также вы можете использовать несколько шаблонов или даже переменных при указании списка слов:

undeceived 30.01.11 в 16:42

1

for x in /etc/r??? /var/lo* /home/drobbins/mystuff/* /tmp/${MYPATH}/*
do
cp $x /mnt/mydira
done

Daemon786 21.01.11 в 09:06

0

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

Daemon786 01.02.11 в 09:46

0

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

Daemon786 01.02.11 в 09:37

0

for x in ../* mystuff/*
do
echo $x is a silly file
done

Daemon786 21.01.11 в 09:06

0

В приведенном выше примере bash выполняет раскрытие шаблонов относительно текущей рабочей директории, также как вы используете относительные пути в командной строке. Поэкспериментируйте немного с подстановкой по шаблону. Вы заметите, что если использовать абсолютные пути, то bash раскроет шаблон в список с абсолютными путями. В противном случае bash будет использовать относительные пути в последующем списке слов. Если вы просто ссылаетесь на файлы в своей рабочей директории (например, вы ввели for x in *), результирующий список файлов не будет начинаться с какой либо информации о пути. Помните, что информация о пути может быть удалена использованием basename, как показано ниже:

Daemon786 01.02.11 в 12:55

0

for x in /var/log/*
do
echo basename $x is a file living in /var/log
done

Daemon786 21.01.11 в 09:06

0

Конечно, часто удобно для выполнения циклов работать с аргументами командной строки сценария. Вот пример того, как использовать переменную "$@", представленную в начале этой статьи.

Daemon786 01.02.11 в 12:58

0

#!/usr/bin/env bash

for thing in "$@"
do
echo you typed ${thing}.
done

вывод:

$ allargs hello there you silly
you typed hello.
you typed there.
you typed you.
you typed silly.

Daemon786 21.01.11 в 09:07

0

Арифметические операции в оболочке

Daemon786 21.01.11 в 09:45

0

Прежде чем обратить внимание на второй тип циклических конструкций, было бы неплохо ознакомиться с выполнением арифметических операций в оболочке. Да, это правда: вы можете выполнять простые математические операции с целыми числами, используя конструкции оболочки. Просто поместите арифметическое выражение между "$((" и "))", и bash вычислит его. Вот несколько примеров:

Daemon786 01.02.11 в 15:50

0

$ echo $(( 100 / 3 ))
33
$ myvar="56"
$ echo $(( $myvar + 12 ))
68
$ echo $(( $myvar - $myvar ))
0
$ myvar=$(( $myvar + 1 ))
$ echo $myvar
57

Daemon786 21.01.11 в 09:07

0

Теперь, когда вы познакомились с выполнением математических операций, настало время представить две другие циклические конструкции в bash, "while" и "until".

Daemon786 01.02.11 в 15:56

0

Больше циклических конструкций: "while" и "until"

Daemon786 01.02.11 в 13:12

0

Оператор "while" выполняется до тех пор, пока условие истинно, и имеет следующий вид:

Daemon786 02.02.11 в 15:38

0

while [ условие ]
do
команды
done

Daemon786 21.01.11 в 09:12

0

while [ условие ]
do
ОПЕРАТОРЫ
done

bugzy 28.02.11 в 14:42

0

Оператор "while" используется, как правило, для выполнения цикла определенного количества раз, как в следующем примере, в котором цикл будет выполнен ровно 10 раз:

Daemon786 03.02.11 в 14:58

0

myvar=0
while [ $myvar -ne 10 ]
do
echo $myvar
myvar=$(( $myvar + 1 ))
done

Daemon786 21.01.11 в 09:07

0
Минутку...

Следующая страница →