Приращение переменной в bash
рассмотрим следующий скрипт:
#!/bin/bash
num=0
cat file | while read line; do
echo "$line"
lines[$num]="$line"
((num++))
echo "num = $num"
done
echo "end num = $num"
i=0
while [ $i -lt $num ]; do
echo "${lines[$i]}"
((i++))
done
обычно он должен читать файл строка за строкой, хранить результат в массиве, затем пройти через массив и распечатать его строка за строкой. Проблема в том, что переменная $num сбрасывается каким-то образом после выхода первого цикла. Вывод этого скрипта для меня следующий (используя файл с каким-то случайным мусором в нем):
dsfkljhhsdfsdfshdjkfgd
num = 1
fdfgdfgdfg
num = 2
dfgdfgdfgdfg
num = 3
dfgdfgdfgdfgdfg
num = 4
dfgdfgdfgdfgdfgd
num = 5
fgdfgdfgdfg
num = 6
dfgdfgdfgdfg
num = 7
dfgdfgdfgdfgdfg
num = 8
dfgdfgdfgdfg
num = 9
dfgdfgdgdgdg
num = 10
dfgdffgdgdgdg
num = 11
end num = 0
почему это? Как добиться запоминания переменной? Я использую bash 3.1.17 на SUSE Linux 10.
3 ответов
почему? Потому что это:
cat file | while read line; do
echo "$line"
lines[$num]="$line"
((num++))
echo "num = $num"
done
работает while
оператор в отдельном процессе, со своей собственной средой, не касаясь родительской среды. Вы также обнаружите, что lines
выбора не было.
следующий упрощенный скрипт показывает это в действии:
#!/bin/bash
export xyzzy=42
echo urk | while read line; do
xyzzy=999
echo $xyzzy
done
echo $xyzzy
вывод этого скрипта:
999
42
потому что установка переменной 999
сделано в подпроцесс.
итог, если вы хотите, чтобы информация отражалась в текущем процессе (скрипте), вам нужно будет выполнить работу на скрипт или найти другой способ получить информацию из подпроцесса.
если вы используете перенаправление ввода, а не запуск конвейера подпроцессов, он должен работать так, как вы хотите. Вот ведь while
бит затем выполняется в контексте настоящее процесс, а не отдельное процесс в конвейере. Например:
#!/bin/bash
export xyzzy=42
while read line; do
xyzzy=999
echo $xyzzy
done <<EOF
hello
EOF
echo $xyzzy
будет:
999
999
для вашего конкретного случая, заменить:
done <<EOF
hello
EOF
С:
done <file
чтобы добавить к предыдущему ответу: и чтобы избежать этого (и UUOC), вам понадобится что-то вроде этого:
while ...; do
...
done < file
просто держите свои переменные все в одной среде. На линии 4, удалить "кошка " файл"|". В строке 9 добавьте "