2015-01-22 2 views
0

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

COUNTER=0 

find . -type f -name "*.txt" | while read f 
do 
    let COUNTER++ 
    echo Counter is $COUNTER # This shows COUNTER working... 
done 

echo Counter is $COUNTER # COUNTER is back to 0 at this point... 

Почему $COUNTER сбросить себя?

+4

Справка из [Bash] Ловушки (http://mywiki.wooledge.org/BashPitfalls#grep_foo_bar_.7C_while_read_-r.3B_do_.28.28count.2B-.2B-. 29.29.3B_done) также [Я устанавливаю переменные в цикле, который находится в конвейере. Почему они исчезают после завершения цикла? Или, почему я не могу передать данные для чтения?] (Http://mywiki.wooledge.org/BashFAQ/024) – kojiro

+0

@nwinkler Хотя ваш предложенный дубликат получил больше голосов, этот вопрос также содержит отвлекающую логическую ошибку. На выбор должны быть десятки других дубликатов, и мои могут быть и не лучшими. – tripleee

+0

@ tripleee Достаточно честно, я заметил, что один и тот же вопрос задавали и отвечали несколько раз, и я выбрал тот, у которого было больше всего голосов :-) – nwinkler

ответ

2

Изменить на:

COUNTER=0 

while read -r entry 
do 
    let COUNTER++ 
    echo Counter is $COUNTER # This shows COUNTER working... 
done < <(find . -type f -name "*.txt") 
2

Внутри цикла создается новая подоболочка, и она имеет другой контекст, чем внешний мир. Уже упомянутый выше page очень хорошо описывает это. Другой ответ by @ arco444 показывает замену процесса обходной путь с этой страницы.

Цитата со страницы, которая имеет отношение к комментариям:

BourneShell создает подоболочку, когда вход или выход чего-либо (петли, случай и т.д ..), но простая команда перенаправляется, либо используя трубопровод или оператор перенаправления ('<', '>').

Таким образом, проблема заключается не в цикле, а в использовании конвейера (|).

+0

знаете ли вы, почему 'bash' использует SubShell для цикла while? – deimus

+0

Я точно не знаю, страница только говорит * В большинстве оболочек каждая команда конвейера выполняется в отдельном SubShell. *. Я предполагаю, что это сводится к способу UNIX: оболочка в основном взаимодействует сот отдельных программ. – meskobalazs

-1

Это также работает:

COUNTER=0 

for line in $(find . -type f -name "*.txt"); 
do 
    let COUNTER++ 
    echo Counter is $COUNTER 
done 
+0

$ COUNTER 0 вне цикла, к сожалению – DanDan

+0

Вероятно, это зависит от оболочки, потому что в моем случае внешний цикл COUNTER не равен 0. Я использую 'GNU bash, версия 4.1.5 (1) -release (x86_64-pc- Linux-гну) ' –

Смежные вопросы