web-dev-qa-db-fra.com

Bash: Comment lire une ligne à la fois depuis la sortie d'une commande?

J'essaie de lire la sortie d'une commande dans bash en utilisant un while loop.

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

La sortie que j'ai

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

Après cela, j'ai essayé

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

mais il a généré une erreur test.sh: line 5: ./test.py: Permission denied.

Alors, comment puis-je le lire ligne par ligne parce que je pense qu'actuellement, il sape la ligne entière à la fois.

Sortie requise:

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

Il y a une erreur, vous avez besoin de < <(command) pas <<<$(command)

< <( ) est un Substitution de processus , $() est un substitution de commande et <<< est une chaîne ici .

59
Gilles Quenot

Notez que rien n'empêche les noms de fichiers de contenir des caractères de nouvelle ligne. La manière canonique d'exécuter une commande pour chaque fichier trouvé par find est.

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

Et si vous voulez que les choses se fassent en bash:

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

De plus, la manière canonique d'appeler la commande "read" dans les scripts (si vous ne voulez pas qu'elle fasse un traitement supplémentaire sur l'entrée) est:

IFS= read -r var

-r consiste à empêcher read de traiter spécialement les barres obliques inverses (comme un caractère d'échappement pour les séparateurs et les sauts de ligne), et IFS = pour définir la liste des séparateurs sur la chaîne vide pour read (sinon si n'importe quel caractère d'espacement était dans cette liste, ils seraient supprimés du début et de la fin de l'entrée).

L'utilisation de boucles dans des shells est généralement une mauvaise idée (pas comment les choses se font dans des shells où vous faites fonctionner plusieurs outils collectivement et simultanément à une tâche plutôt que d'exécuter un ou plusieurs outils des centaines de fois dans l'ordre).

14
Stéphane Chazelas

Il n'y a pas besoin de substitution de commande si vous souhaitez utiliser le canal:

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

Bien que comme déjà indiqué, dans le cas de find vous feriez mieux avec son -exec option.

0