Обнуление переменной на выходе из цикла

Изображение пользователя DRVTiny.
Опубликовано:
Раздел:

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

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

cnt=0; echo "Before: $cnt"
cat /etc/fstab | \
while read l; do
((cnt++))
echo $cnt
done
echo "After: $cnt"

Перед циклом обнуляем значение переменной-счётчика, дальше на каждой новой итерации цикла наращиваем его и посылаем значение в stdout, затем после выхода из цикла печатаем результирующее значение счётчика, и... упс, а оно обнулилось!!!

Пожалуйста, объясните мне кто-нибудь, почему, собственно, так происходит в BASH - ведь цикл в меру моего разумения данного вопроса должен относиться к той же области видимости, что и echo в конце???



Эй, оператор-астроном,

Нет звёзд и звёздных глаз -

Есть плац, пивная, гастроном

И горы из колбас!

Марк Мерман, "Никто кино так не снимал, как Лени Риффеншталь"

Изображение пользователя ks.

Re: Обнуление переменной на выходе из цикла #1

cnt=0; echo "Before: $cnt"
cat /etc/fstab | \\
while read l; do
((cnt++))
echo $cnt
done

Для создания анонимного канала выполняется fork, т.е. изменение cnt происходит в дочернем процессе. Мы имеем две переменных в разных процессах.

решается переопределением stdin для while:

cnt=0; echo "Before: $cnt"
while read l; do
((cnt++))
echo $cnt
done < /etc/fstab
echo "After: $cnt"

или неявное создание именованного канала <(command):

cnt=0; echo "Before: $cnt"
while read l; do
((cnt++))
echo $cnt
done < <(cat /etc/fstab)
echo "After: $cnt"

либо явно:

cnt=0; echo "Before: $cnt"
mkfifo /tmp/tmp.$$
cat /etc/fstab > /tmp/tmp.$$ &
while read l; do
((cnt++))
echo $cnt
done < /tmp/tmp.$$
rm /tmp/tmp.$$
echo "After: $cnt"


Поехали!
JID: konst.su [обезьяна] gmail.com

Изображение пользователя DRVTiny.

Re: Обнуление переменной на выходе из цикла #2

Спасибо, ks, за столь подробный и обстоятельный ответ. Лишний раз убедился в том, что хотя на языке командной оболочки можно делать всё, у скриптового программирования есть, к сожалению, множество "подводных камней", котороые возникают из-за того, что BASH - всё-таки не полноценный язык, подобный Perl, а скорее просто надстройка командной строки.


Эй, оператор-астроном,
Нет звёзд и звёздных глаз -
Есть плац, пивная, гастроном
И горы из колбас!

Марк Мерман, "Никто кино так не снимал, как Лени Риффеншталь"

Изображение пользователя IsakovAN.

Обнуление переменной на выходе из цикла #3

DRVTiny писал(а):
Спасибо, ks, за столь подробный и обстоятельный ответ. Лишний раз убедился в том, что хотя на языке командной оболочки можно делать всё, у скриптового программирования есть, к сожалению, множество "подводных камней", котороые возникают из-за того, что BASH - всё-таки не полноценный язык, подобный Perl, а скорее просто надстройка командной строки.
Не. Это из-за нежелания думать и читать доки! Катается от смеха И код кривой. Надо было cnt=`wc -l /etc/fstab` Улыбка