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

Аватар пользователя 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: Обнуление переменной на выходе из цикла

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"

Аватар пользователя DRVTiny

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

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

Аватар пользователя IsakovAN

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

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

Не. Это из-за нежелания думать и читать доки! Катается от смеха
И код кривой. Надо было cnt=`wc -l /etc/fstab` Улыбка

RSS-материал