Bash: Как прочитать одну строку за раз из вывода команды?


49

Я пытаюсь прочитать вывод команды в Bash, используя while loop.

while read -r line
do
    echo "$line"
done <<< $(find . -type f)

На выходе я получил

ranveer@ranveer:~/tmp$ bash test.sh
./test.py ./test1.py ./out1 ./test.sh ./out ./out2 ./hello
ranveer@ranveer:~/tmp$ 

После этого я попробовал

$(find . -type f) | 
while read -r line
do
    echo "$line"
done 

но это породило ошибку test.sh: line 5: ./test.py: Permission denied.

Итак, как я могу прочитать это построчно, потому что я думаю, что в настоящее время он глотает всю строку сразу.

Требуемый выход:

./test.py
./test1.py
./out1
./test.sh
./out
./out2
./hello

3
Я предлагаю прочитать Bash FAQ 01 - много полезной информации и советов о ловушках, которых следует избегать.
jw013

Для while readчасти, см. Понимание IFS и вопросы, связанные там.
Жиль "ТАК - перестань быть злым"

Ответы:


54

Там есть ошибка, вам < <(command)не нужно<<<$(command)

< <( )это процесс Замена , $()является заменой команды и <<<является здесь строкой .


2
@RanRag Хватит пытаться $( )обойти все! Это синтаксис подстановки команд , который является единственным способом использования вывода команды. Каналы и подстановки процессов, а также строки здесь - это другие, и все они имеют разный синтаксис, естественно. В любом случае вам не следует разбирать имена файлов, если вы действительно не знаете, что делаете.
jw013

Спасибо, это сработало, узнаем больше о Process Substitution.
RanRag

@ jw013: я новичок в bash. В будущем буду держать ваше предложение в моей памяти.
RanRag

13

Обратите внимание, что ничто не мешает именам файлов содержать символы новой строки. Канонический способ выполнить команду для каждого найденного файла - это.

find . -type f -exec cmd {} \;

И если вы хотите, чтобы все было сделано в bash:

find . -type f -exec bash -c '
  for file do
    something with "$file"
  done' bash {} +

Кроме того, канонический способ вызова команды «read» в скриптах (если вы не хотите, чтобы она выполняла дополнительную обработку входных данных):

IFS= read -r var

-rдолжен прекратить readобрабатывать символы обратной косой черты специально (как escape-символы для разделителей и новой строки), а IFS = установить список разделителей для пустой строки для read(в противном случае, если какой-либо символ пробела был в этом списке, они будут удалены из начало и конец ввода).

Использование циклов в оболочках, как правило, плохая идея (а не то, как все делается в оболочках, когда вы заставляете несколько инструментов работать совместно и параллельно для выполнения задачи, а не запускать один или несколько инструментов сотни раз подряд).

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.