Почему этот цикл For не совпадает с циклом while в Bash? - PullRequest
3 голосов
/ 10 декабря 2011

Хорошо, я пытаюсь проанализировать файл, который выводит в столбцах то, что мне нужно в строках, и я не могу заставить этот цикл while работать, и я действительно в замешательстве.

Интересно, что почти то же самое с циклом for работает .Может кто-нибудь объяснить, что здесь происходит?

Это ...

e=""
for f in 1 2 3
do 
    echo $f 
    e="$e.$f"
done
echo $e

Выходы:

1
2
3
.1.2.3

Но это ...

e=""
echo "1
2
3" | while read f
do 
    echo $f 
    e="$e.$f"
done
echo $e

Выходы:

1
2
3

Очевидно, что оба цикла имеют 1, 2 или 3 в $f, когда они достигают e="$e.$f", так что, черт возьми, происходит, что второй не делаетработа

Ответы [ 4 ]

8 голосов
/ 10 декабря 2011

Я не могу сказать вам, сколько раз мне приходилось вытаскивать эту ошибку из чьего-либо кода.

По сути, канал генерирует раздвоенный процесс.e устанавливается в разветвленном процессе, но когда он завершается (в конце цикла wile), родительский процесс не знает, что e изменилось.Короче говоря, никогда не устанавливайте переменную в команде, включающей канал.Он не будет установлен, когда закончится труба.Короче ... Не используйте трубы, если их можно избежать.

e=''
while read f
do
  echo $f
  e="$e.$f"
done << EOF
1
2
3
EOF
echo $e
3 голосов
/ 10 декабря 2011

Поскольку while read... done является частью конвейера, он получает свой собственный раздвоенный образ процесса, как и другие двоичные файлы (это называется subshell ). (Смущает то, что она написана в оболочке, но, тем не менее, она не выполняется как часть текущего процесса оболочки.) Именно поэтому переменные не будут получать обновления.

в качестве обходного пути, вы всегда можете сделать что-то вроде этого (использует bashisms):

while read line
do
    blablabla
done < <(echo "1 2 3")

Здесь вы избегаете настройки конвейера, поэтому код оболочки while...done выполняется как часть вашего текущего сценария.

3 голосов
/ 10 декабря 2011
Труба

будет выполнена в подоболочке. поэтому переменная e не была изменена после выполнения переданной команды.

1 голос
/ 10 декабря 2011

Я предполагаю, что это различие в объеме переменных.Когда вы передаете свой оператор echo в оператор while, глобальный e не находится в его области видимости, поэтому он печатает f и устанавливает новую переменную e.Когда цикл while завершается, глобальный e не изменяется.Следовательно, ваше утверждение echo $e ничего не печатает.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...