Первый пост в моем журнале на компьютерную тему. Вообще то я таки да, системный администратор, но почему то до сих пор мне удавалось хорошо замаскироваться под обычного человека. Ну если не совсем человека, то хотя бы позвоночно-прямоходящее и иногда разумное существо. Но последнии пару дней меня мучал один вопрос (не про то, откуда взять большую кучу денег, этот вопрос меня мучает все время и достаточно долго). Довелось мне на днях придумать на свою голову написать что-нибудь полезное в моем любимом bash-е. Ну тот, который стандартная оболочка Линукса. Но не в Линуксе, а в (тоже любимом) Солярисе. Вот такой кусочек загубил разом мою молодость и красоту - я поседел процентов на 10, пытаясь понять, в чем же дело:
counter=0
grep arc test.txt | while read var[$counter];
do
counter=$(( $counter + 1 ))
done
Т.е. все просто - вытаскиваются все строки, содержащие "arc"из файла test.txt (по секрету - в каждой строке всего одно слово, для простоты) и присваиваются порядковым элементам массива. Казалось бы - все просто, все должно работать. Ан нет - если вставить в серединку этого while цикла такую вещь
echo $counter
echo ${var[$counter]}
то видно, что все работает. Ну то-есть на уровне цикла. А на выходе цикла - шиш! Обнуляется счетчик и массив пустой. Что за фигня?! И главное - почему то тоже самое в ksh работает на ура? В чем подвох?
А все оказалось просто. Хитрый bash при передачи данных через каналы pipe создает новый подпроцесс-оболочку для цикла, в который переменные локальны и переходить на высокий уровень не хотят. Что-бы этого не произошло, предлагаются такие варианты:
counter=0
while read var[$counter];
do
counter=$(( $counter + 1 ))
done < <(grep arc test.txt)
ну или еще проще:
counter=0
all_arcs=$(grep arc test.txt)
for i in $all_arcs;
do
var[$counter]=$i
counter=$(( counter + 1 ))
done
Вот так все становится на свои места. А потому, что надо читать инструкции и не надеяться на то, что все будет так, как хочется:
http://www.opennet.ru/docs/RUS/bash_scripting_guide/c12434.html