Itération sur chaque ligne de sortie ls -l

120

Je veux parcourir chaque ligne dans la sortie de: ls -l /some/dir/*

En ce moment, j'essaye: for x in $(ls -l $1); do echo $x; done

Cependant, cela itère sur chaque élément de la ligne séparément, donc j'obtiens:

-r--r-----
1
ivanevf
eng
1074
Apr
22
13:07
File1

-r--r-----
1
ivanevf
eng
1074
Apr
22
13:17
File2

Mais je veux parcourir chaque ligne dans son ensemble, cependant. Comment je fais ça?

Ivan
la source
1
Citez toujours les variables (et la sortie de commande) sauf si vous avez une raison spécifique de ne pas le faire.
glenn jackman

Réponses:

247

Définissez IFS sur une nouvelle ligne, comme ceci:

IFS='
'
for x in `ls -l $1`; do echo $x; done

Mettez un sous-shell autour de lui si vous ne voulez pas définir IFS de manière permanente:

(IFS='
'
for x in `ls -l $1`; do echo $x; done)

Ou utilisez while | lire à la place:

ls -l $1 | while read x; do echo $x; done

Une autre option, qui exécute while / read au même niveau du shell:

while read x; do echo $x; done << EOF
$(ls -l $1)
EOF
Randy Proctor
la source
12
Méfiez-vous lors du piping vers while, le while s'exécutera dans un sous-shell, ce qui signifie qu'il ne pourra pas changer les variables dans le processus principal
Reorx
1
Que fait le dollar ici? J'ai besoin de l'utiliser dans un script que j'écris qui accepte les arguments. Le $ 1 jette les choses. Que puis-je mettre là au lieu de 1 $ pour obtenir le même effet? Je voudrais utiliser la deuxième solution.
noob-in-need
@ noob-in-need Remplacez-le par le répertoire que vous voulez lister
vpzomtrrfrt
1
Vous voudrez peut-être faire, read -rsinon bash supprimera les contre-obliques non échappées des données.
Brian Gordon
6

Cela dépend de ce que vous voulez faire avec chaque ligne. awk est un utilitaire utile pour ce type de traitement. Exemple:

 ls -l | awk '{print $9, $5}'

.. sur mon système imprime le nom et la taille de chaque élément du répertoire.

Adam Holmberg
la source
3

Comme déjà mentionné, awk est le bon outil pour cela. Si vous ne voulez pas utiliser awk, au lieu d'analyser la sortie de "ls -l" ligne par ligne, vous pouvez parcourir tous les fichiers et faire un "ls -l" pour chaque fichier individuel comme ceci:

for x in * ; do echo `ls -ld $x` ; done
Axel
la source
3

Vous pouvez également essayer la findcommande. Si vous ne voulez que des fichiers dans le répertoire courant:

find . -d 1 -prune -ls

Exécuter une commande sur chacun d'eux?

find . -d 1 -prune -exec echo {} \;

Compter les lignes, mais uniquement dans les fichiers?

find . -d 1 -prune -type f -exec wc -l {} \;

David Koski
la source
trouver est cassé. Je reçois souvent des messages d'erreur bizarro. il veut m'aider lorsque la ligne de commande est parfaitement valide, et il semble qu'une fois qu'il commence à le faire, il ne s'arrêtera pas avant le prochain redémarrage PEUT-ÊTRE. il semble parfois de nature aléatoire concernant les erreurs. ne sais pas comment je peux signaler le bogue.
Jim Michaels
1

L'utilitaire read (1) avec la redirection de sortie de la commande ls (1) fera ce que vous voulez.

Steve Emmerson
la source
-1

Alors, pourquoi personne n'a suggéré d'utiliser simplement des options qui éliminent les parties qu'il ne veut pas traiter.

Sur Debian moderne, vous obtenez simplement votre fichier avec:

ls --format=single-column 

De plus, vous n'avez pas à faire attention au répertoire dans lequel vous l'exécutez si vous utilisez le répertoire complet:

ls --format=single-column /root/dir/starting/point/to/target/dir/

Cette dernière commande que j'utilise ci-dessus et j'obtiens la sortie suivante:

bot@dev:~/downloaded/Daily# ls --format=single-column /home/bot/downloaded/Daily/*.gz
/home/bot/downloaded/Daily/Liq_DailyManifest_V3_US_20141119_IENT1.txt.gz
/home/bot/downloaded/Daily/Liq_DailyManifest_V3_US_20141120_IENT1.txt.gz
/home/bot/downloaded/Daily/Liq_DailyManifest_V3_US_20141121_IENT1.txt.gz
BradChesney79
la source