Bash: come leggere una riga alla volta dall'output di un comando?


49

Sto cercando di leggere l'output di un comando in bash usando a while loop.

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

L'output che ho ottenuto

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

Dopo questo ho provato

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

ma ha generato un errore test.sh: line 5: ./test.py: Permission denied.

Quindi, come posso leggerlo riga per riga perché penso che attualmente stia bevendo l'intera riga in una volta.

Uscita richiesta:

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

3
Suggerisco di leggere le FAQ 01 di Bash - molte informazioni utili e consigli sulle trappole da evitare.
jw013,

Per la while readparte, vedere Informazioni su IFS e le domande ad esso collegate.
Gilles 'SO- smetti di essere malvagio' il

Risposte:


54

C'è un errore, è necessario < <(command)non<<<$(command)

< <( )è una sostituzione di processo , $()è una sostituzione di comando ed <<<è una stringa qui .


2
@RanRag Smetti di provare a mettere $( )tutto intorno! Questa è la sintassi per la sostituzione dei comandi , che è solo un modo per utilizzare l'output dei comandi. I tubi, la sostituzione del processo e le stringhe qui sono altri, e tutti hanno sintassi diversa, naturalmente. Non dovresti comunque analizzare i nomi dei file se non sai davvero cosa stai facendo.
jw013,

Grazie ha funzionato leggerà di più Process Substitution.
RanRag

@ jw013: sono un principiante bash. In futuro manterrò il tuo suggerimento nella mia mente.
RanRag

13

Nota che non c'è nulla che impedisce ai nomi dei file di contenere caratteri di nuova riga. Il modo canonico per eseguire un comando per ogni file trovato da find è.

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

E se vuoi che le cose vengano fatte in bash:

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

Inoltre, il modo canonico di chiamare il comando "read" negli script (se non si desidera che esegua un'ulteriore elaborazione sull'input) è:

IFS= read -r var

-rè quello di interrompere il readtrattamento di caratteri di barra rovesciata appositamente (come carattere di escape per separatori e newline), e IFS = per impostare l'elenco di separatori sulla stringa vuota per read(altrimenti se un carattere di spazio bianco fosse in quell'elenco, verrebbero rimossi dal inizio e fine dell'input).

L'uso dei loop nelle shell è di solito una cattiva idea (non come vengono fatte le cose nelle shell in cui si fanno lavorare più strumenti collettivamente e contemporaneamente a un'attività piuttosto che eseguire uno o più strumenti centinaia di volte in sequenza).

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.