Comment sortir uniquement les noms de fichiers (avec des espaces) dans ls -Al?


80

Je devrais faire écho uniquement aux noms de fichiers ou de répertoires avec cette construction:

ls -Al | while read string
do
...
done

ls -Al sortie:

drwxr-xr-x  12 s162103  studs         12 march 28 12:49 personal domain
drwxr-xr-x   2 s162103  studs          3 march 28 22:32 public_html
drwxr-xr-x   7 s162103  studs          8 march 28 13:59 WebApplication1

Par exemple si j'essaye:

ls -Al | while read string
do
echo "$string" | awk '{print $9}
done

puis ne produire que des fichiers et des répertoires sans espaces. Si le fichier ou le répertoire contient des espaces tels que "domaine personnel", il ne s'agira que du mot "personnel".

J'ai besoin d'une solution très simple. Peut-être qu'il y a une meilleure solution que awk.


2
Pourquoi pas juste ls -Al *' '*? lsLa sortie de l' analyse ne mène à rien de bon.
manatwork

1
Si vous avez besoin de quelque chose qui marchera dans n'importe quel * nix, essayez d'éviter de l'utiliser ls -Al | while. Un moyen simple et plus fiable est for string in *; do echo "$string"; done.
forcefsck

besoin seulement de cette construction..okay, pas simple, aucune solution!
Alex Zern

1
Pourquoi avez-vous besoin ls ? L'analyse syntaxique lset le "travail dans tout * nix et ne cassera pas si quelque chose s'est passé" ne vont pas bien ensemble.
terdon

Réponses:


99

Vous ne devriez vraiment pas analyser la sortie dels . S'il s'agit d'un devoir et que vous y êtes tenu, votre professeur ne sait pas de quoi ils parlent. Pourquoi ne fais-tu pas quelque chose comme ça:

Le bon...

find ./  -printf "%f\n"

ou

for n in *; do printf '%s\n' "$n"; done

...le mauvais...

Si vous voulez vraiment utiliser ls, vous pouvez le rendre un peu plus robuste en faisant quelque chose comme ceci:

ls -lA | awk -F':[0-9]* ' '/:/{print $2}'

... et le laid

Si vous insistez pour le faire de manière incorrecte et dangereuse et que vous devez simplement utiliser une whileboucle, procédez comme suit:

ls -Al | while IFS= read -r string; do echo "$string" | 
    awk -F':[0-9]* ' '/:/{print $2}'; done

Sérieusement, ne le faites pas.


drwx------ 2 s162103 studs 3 oct. 9 2012 .ssh drwxr-xr-x 3 s162103 studs 6 oct. 25 09:02 .subversion drwxrwxrwt 3 s162103 studs 3 nov. 15 2012 .TempoItemsParfois, j'ai rendez-vous sans heure, seulement l'année et le retour gawk sont vides
Alex Zern

1
@ AlexZern Eh bien, c'est l'une des raisons pour lesquelles vous n'analysez pas la sortie ls.
terdon

2
@AlexZern pourquoi avez-vous besoin de l' -linterrupteur quand même? Si tout ce que vous voulez, ce sont les noms de fichiers, lancez simplement ls -A. Utiliser -lvous rend la vie plus difficile car vous devez maintenant analyser la sortie.
terdon

parce que j'ai besoin d'informations supplémentaires telles que l'accès, la date, le propriétaire, etc. Et j’ai écrit un énorme script, qui fonctionne bien, à l’exception des noms de fichiers d’impression et de noms de répertoire avec des espaces.
Alex Zern

3
Alors ok. Ce que nous avons ici est un problème XY . lsn’est tout simplement pas le meilleur moyen d’obtenir ce dont vous avez besoin. Pourquoi ne postez-vous pas une nouvelle question expliquant les informations que vous souhaitez collecter et nous pouvons suggérer des moyens de le faire. Sinon, vous pouvez utiliser votre script tel quel et utiliser l'une des suggestions ci-dessus pour n'imprimer que le nom. Mais sérieusement, ne pas analyser ls, dites-nous exactement ce que vous essayez de faire dans une nouvelle question.
terdon

74

Y a-t-il une raison pour laquelle ls -A1* ne fonctionnera pas?

Par exemple:

$ touch file1 file2 file\ with\ spaces
$ ls -Al
total 0
-rw-r--r-- 1 bahamat bahamat 0 Mar 30 22:31 file1
-rw-r--r-- 1 bahamat bahamat 0 Mar 30 22:31 file2
-rw-r--r-- 1 bahamat bahamat 0 Mar 30 22:31 file with spaces
$ ls -A1
file1
file2
file with spaces
$

* Remarque: il s’agit d’une lettre majuscule A et du numéro un.


4
le -1 c'est le génie. Je ne savais pas qu'il était disponible. (Je sais que je sais. RTFM)
The Lazy Coder

cela ne fonctionne que pour le répertoire courant si vous voulez lister les noms de fichiers d'un autre répertoire, par exemple ~ / projets, vous obtiendrez des chemins complets au lieu des noms de fichiers
thecotne

@thecotne sur Mac 10.9.5, il ne fait que lister les noms de fichiers. Quel système d'exploitation utilisez-vous?
AJP

je cours cette ls ~ / projets / * -A1 sublime projet pour ls ~ / projets -A1 i ne reçoivent que des noms.
thecotne

3
@TheLazyCoder ne devrait pas lire le manuel.
c24w

41

Je me demande pourquoi personne n'a mentionné cette commande simple:

ls -a | sort

2
Brillant! Avez-vous une idée de la façon dont la tuyauterie sortempêche le bloc multi-colonnes de devenir une seule colonne?
msciwoj

@msciwoj prend juste des chaînes séparées par des espaces et les imprime triées par lignes de fond
Ben

PARFAIT! Pourquoi celui-ci n'a-t-il pas été marqué comme la vraie réponse!?
夏期劇場

3
Cela fonctionne ici parce que lsrevient à ls -1(sortie à une seule colonne) lorsque sa sortie ne va pas à un terminal (et désactive la citation / remplacement de caractères non imprimables; @Kusalananda, votre lsn'est pas conforme à POSIX s'il le fait toujours). lsla sortie est déjà triée. Donc, si vous sortle faites, au mieux, vous ne ferez rien, et au pire, modifiez le résultat (si les noms de fichiers contiennent des caractères de nouvelle ligne) ou échouez pour les noms de fichiers qui ne sont pas du texte. ls -a | catserait mieux. Ou encore mieux ls -A1comme déjà mentionné (et parce que vous voulez généralement les remplacements / citations lorsqu'ils sont affichés sur un terminal)
Stéphane Chazelas

1
@ StéphaneChazelas noté. lsse comporte différemment lorsque la sortie n'est pas un terminal.
Kusalananda

3

Vous ne pouvez pas analyser la sortie de ls, sans parler de ls -lnouvelle ligne, tout comme l'espace est un caractère aussi valide que n'importe quel nom de fichier. En outre, vous devrez considérer les liens symboliques qui ont une sortie telle que ... foo -> bar.

Pourquoi voudriez-vous utiliser -lquand même si vous ne voulez que le nom du fichier?

Il suffit de faire:

for file in *; do
  ...
done

Si vous souhaitez inclure des fichiers de points (sauf .et ..), en fonction du shell:

zsh:

for file in *(ND); do
  ...
done

bash:

shopt -s nullglob dotglob
for file in *; do
  ...
done

ksh93:

FIGNORE='@(.|..)'
for file in ~(N)*; do
  ...
done

POSIXly:

for file in .[!.]* ..?* *; do
  [ -e "$file" ] || [ -L "$file" ] || continue
  ...
done


1
ls -Al | tr -s ' ' | cut -f9- -d' '

compresser plusieurs espaces en espaces simples avec tr, vous pouvez utiliser couper pour diviser sur les champs


1

Essayez ( bash, zsh, ksh93syntaxe):

find . -type f -print0 | while IFS= read -r -d '' filename; do
  ...
done

Cela devient récursif et ne répertorie que les fichiers normaux (c'est-à-dire, aucun répertoire ou lien symbolique / fifos / devices ...).

Voir également:



-1
ls --file *|grep ^ 

il affiche quels fichiers dans quel répertoire.


Je ne pense pas que cela répond à la question.
Jeff Schaller
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.