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

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

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

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

Daemon786 03.02.11 в 15:01

0

Оператор "until" предоставляет обратную функциональность оператору "while". Он выполняется до тех пор, пока условие ложно. Здесь цикл "until" выполняет те же функции, как и предыдущий цикл "while":

Daemon786 03.02.11 в 15:13

0

myvar=0
until [ $myvar -eq 10 ]
do
echo $myvar
myvar=$(( $myvar + 1 ))
done

Daemon786 21.01.11 в 08:07

0

Оператор "case"

Daemon786 21.01.11 в 09:36

0

Оператор "case" еще одна удобная условная конструкция. Вот фрагмент примера:

Daemon786 03.02.11 в 15:19

0

case "${x##*.}" in
gz)
gzunpack ${SROOT}/${x}
;;
bz2)
bz2unpack ${SROOT}/${x}
;;
*)
echo "Archive format not recognized."
exit
;;
esac

Daemon786 21.01.11 в 08:08

0

В приведенном примере, bash сначала раскрывает "${x##*.}". В коде "$x" -- это имя файла, а "${x##*.}" удаляет весь текст за исключением того, что следует за последней точкой в имени файла. Затем bash сравнивает получившуюся строку с переменными, перечисленными слева от ")". В данном случае "${x##*.}" сравнивается с "gz", далее с "bz2" и, наконец, с "*". Если "${x##*.}" соответствует какой-нибудь из этих строк или шаблонов, то код, следующий непосредственно за ")", будет выполняться до ";;", после чего bash продолжит выполнять программу после завершающего слова "esac". Если ни шаблоны, ни строки не совпадают, то ни одной строки кода не выполняется, однако в данном фрагменте, по крайней мере, один блок кода будет выполнен, потому что шаблон "*" будет ловить всё, что не соответствует "gz" и "bz2".

Daemon786 03.02.11 в 15:28

0

Функции и пространства имен

Daemon786 21.01.11 в 09:36

0

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

Daemon786 04.02.11 в 14:21

0

tarview() {
echo -n "Displaying contents of $1 "
if [ ${1##*.} = tar ]
then
echo "(uncompressed tar)"
tar tvf $1
elif [ ${1##*.} = gz ]
then
echo "(gzip-compressed tar)"
tar tzvf $1
elif [ ${1##*.} = bz2 ]
then
echo "(bzip2-compressed tar)"
cat $1 | bzip2 -d | tar tvf -
fi
}

Daemon786 21.01.11 в 08:09

0

Примечание:
Другой случай: приведенный код может быть написан с использованием оператора "case". Можете ли вы сказать каким образом?

Daemon786 04.02.11 в 14:42

0

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

Daemon786 04.02.11 в 15:23

0
+1

$ tarview shorten.tar.gz
Displaying contents of shorten.tar.gz (gzip-compressed tar)
drwxr-xr-x ajr/abbot 0 1999-02-27 16:17 shorten-2.3a/
-rw-r--r-- ajr/abbot 1143 1997-09-04 04:06 shorten-2.3a/Makefile
-rw-r--r-- ajr/abbot 1199 1996-02-04 12:24 shorten-2.3a/INSTALL
-rw-r--r-- ajr/abbot 839 1996-05-29 00:19 shorten-2.3a/LICENSE
....

Daemon786 04.02.11 в 17:08

0

Как вы можете видеть, внутри функции можно ссылаться на аргументы, используя тот же механизм, который используется для ссылки на аргументы командной строки. Кроме того, "$#" будет содержать в себе количество аргументов. Единственное, что может работать не так, как ожидалось, это переменная "$0", которая будет раскрыта как строка "bash" (если вы запустили функцию из оболочки интерактивно) или как имя сценария, в котором вызвана функция.

Daemon786 09.02.11 в 09:50

0

Примечание:
Используйте их интерактивно: не забывайте, что функции такие, как приведенная выше, могут быть размещены в файлах ~/.bashrc или ~/.bash_profile так, что они будут доступны для использования всякий раз, когда вы находитесь в bash.

Daemon786 06.02.11 в 11:36

0

Пространство имен

Daemon786 21.01.11 в 09:36

0

Часто вам необходимо создать переменную окружения внутри функции. Если возможно, то запомните эту техническую особенность. В большинстве компилируемых языков программирования (таких как C), когда вы создаете переменную внутри функции, она будет расположена в отдельном локальном пространстве имен. Таким образом, если вы определите функцию в C с названием myfunction и в ней определите переменную с именем "x", то любая глобальная (за пределами функции) переменная с именем "x" не будет зависеть от нее, что устранит побочный эффект.

Daemon786 06.02.11 в 12:32

0

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

Daemon786 06.02.11 в 15:22

0

#!/usr/bin/env bash

myvar="hello"

myfunc() {

myvar="one two three"
for x in $myvar
do
echo $x
done
}

myfunc

echo $myvar $x

Daemon786 21.01.11 в 08:09

0

Когда этот сценарий запустится, он выведет "one two three three", показывая, как определенная в функции "$myvar" затерла глобальную переменную "$myvar", и как переменная контроля цикла "$x" продолжила существовать даже после завершения работы функции (и также затерла бы глобальную "$x", если та была определена).

Daemon786 06.02.11 в 16:09

0

Когда этот сценарий запустится, он выведет "one two three three", показывая, как определенная в функции "$myvar" затерла глобальную переменную "$myvar", и как переменная контроля цикла "$x" продолжила существовать даже после завершения работы функции (и также затерла бы глобальную "$x", если та была определена).

Daemon786 06.02.11 в 16:09

0

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

Daemon786 06.02.11 в 16:31

0

#!/usr/bin/env bash

myvar="hello"

myfunc() {
local x
local myvar="one two three"
for x in $myvar
do
echo $x
done
}

myfunc

echo $myvar $x

Daemon786 21.01.11 в 08:10

0

Эта функция будет выводить "hello" -- глобальная переменная "$myvar" не была перезаписана, и "$x" не продолжает существовать вне myfunc. В первой строке функции мы создаем локальную переменную x, которую используем позднее, в то время как, во втором случае (local myvar="one two three") мы создаем локальную переменную myvar и присваиваем ей значение. Первая форма удобна для хранения локальных переменных контроля цикла, так как недопустимо писать "for local x in $myvar". Данная функция не перезапишет никаких глобальных переменных, и вам рекомендуется разрабатывать таким образом все ваши функции. Вы не должны использовать "local" только в тех случаях, когда явно хотите изменить глобальную переменную.

Daemon786 06.02.11 в 17:13

0

В заключение

Daemon786 21.01.11 в 09:39

0

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

Daemon786 06.02.11 в 12:02

0

Ресурсы

Daemon786 21.01.11 в 09:34

0

Полезные ссылки
* Bash в примерах: Часть 1.
* Bash в примерах: Часть 3.
* Посетите домашнюю страницу GNU bash.

Daemon786 21.01.11 в 09:35

0

Дэниэль Роббинс
Дэниэль Роббинс — основатель сообщества Gentoo и создатель операционной системы Gentoo Linux. Дэниэль проживает в Нью-Мехико со свой женой Мэри и двумя энергичными дочерьми. Он также основатель и глава Funtoo, написал множество технических статей для IBM developerWorks, Intel Developer Services и C/C++ Users Journal.

Daemon786 21.01.11 в 09:35

0
Минутку...

← Предыдущая страница