Bash: Comment lire une ligne à la fois à partir du résultat d'une commande?

49

J'essaie de lire le résultat d'une commande en bash en utilisant un fichier while loop.

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

La sortie que j'ai eu

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 cela 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’à l’heure actuelle, il est en train d’embrasser toute la ligne en même temps.

Sortie requise:

./test.py
./test1.py
./out1
./test.sh
./out
./out2
./hello
RanRag
la source
3
Je suggère de lire la FAQ Bash 01 - une foule d’informations utiles et de conseils sur les pièges à éviter.
Jw013
Pour la while readpartie, voir Comprendre IFS et les questions qui y sont liées.
Gilles 'SO- arrête d'être méchant'
Pour utiliser find, voir Comment utiliser deux commandes bash dans l'option -exec de la commande find? ou Exécution d'une fonction définie par l'utilisateur dans un appel find -exec (dont cette question est principalement une copie).
Gilles 'SO- arrête d'être méchant'

Réponses:

54

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

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

Gilles Quenot
la source
2
@RanRag Arrêtez d'essayer de tout mettre en place $( )! C'est la syntaxe de la substitution de commande , qui n'est qu'un moyen d'utiliser le résultat de la commande. Tuyaux et processus de substitution et ici-chaînes en sont d'autres, et ils ont tous une syntaxe différente, naturellement. De toute façon, vous ne devriez pas analyser les noms de fichiers, sauf si vous savez vraiment ce que vous faites.
Jw013
Merci cela a fonctionné lira plus au sujet de Process Substitution.
RanRag
@ jw013: Je suis un débutant bash. À l'avenir, garderez votre suggestion dans mon esprit.
RanRag
13

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 à Bash:

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

En outre, la manière canonique d’appeler la commande "read" dans les scripts (si vous ne souhaitez pas qu’elle effectue un traitement supplémentaire sur l’entrée) est la suivante:

IFS= read -r var

-rdoit cesser readde traiter les caractères de barre oblique inverse spécialement (comme un caractère d'échappement pour les séparateurs et les nouvelles lignes), et IFS = pour définir la liste des séparateurs sur la chaîne vide read(sinon, si un caractère d'espacement était dans cette liste, ils seraient supprimés début et fin de la saisie).

Utiliser des boucles dans les shells est généralement une mauvaise idée (pas comment les choses se font dans des shells dans lesquels plusieurs outils fonctionnent simultanément et simultanément pour une tâche plutôt que d'exécuter un ou plusieurs outils des centaines de fois de suite).

Stéphane Chazelas
la source