Wie kann man in ls -Al nur Dateinamen (mit Leerzeichen) ausgeben?

78

Ich sollte nur Namen von Dateien oder Verzeichnissen mit dieser Konstruktion ausgeben:

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

ls -Al Ausgabe :

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

Zum Beispiel, wenn ich versuche:

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

dann nur Dateien und Verzeichnisse ohne Leerzeichen ausgeben. Wenn eine Datei oder ein Verzeichnis Leerzeichen wie "Persönliche Domain" enthält, ist dies nur das Wort "Persönlich".

Ich brauche eine sehr einfache Lösung. Vielleicht gibt es eine bessere Lösung als awk.

Alex Zern
quelle
2
Warum nicht einfach ls -Al *' '*? lsDie Ausgabe von Parsing führt nie zu etwas Gutem.
Manatwork
1
Wenn Sie etwas benötigen, das in jedem * nix funktioniert, vermeiden Sie die Verwendung ls -Al | while. Ein einfacher und zuverlässiger Weg ist for string in *; do echo "$string"; done.
Forcefsck
brauche nur mit dieser konstruktion..okay, nicht einfach, keine lösung!
Alex Zern
1
Warum Sie brauchen ls ? Parsing lsund "Arbeit in allen * nix und wird nicht brechen, wenn etwas passiert" passen nicht gut zusammen.
Terdon

Antworten:

97

Sie sollten die Ausgabe von wirklich nicht analysierenls . Wenn dies eine Hausaufgabe ist und Sie dazu aufgefordert werden, weiß Ihr Professor nicht, wovon sie sprechen. Warum machst du nicht so etwas:

Der gute...

find ./  -printf "%f\n"

oder

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

...das Schlechte...

Wenn Sie wirklich wirklich verwenden möchten ls, können Sie es ein wenig robuster machen, indem Sie Folgendes tun:

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

... und das hässliche

Wenn Sie darauf bestehen , es auf die falsche, gefährliche Weise zu tun, und nur eine whileSchleife verwenden müssen, gehen Sie folgendermaßen vor:

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

Aber im Ernst, tu es einfach nicht.

terdon
quelle
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 .TempoItemsmanchmal habe ich date ohne zeit, nur jahr und gawk kehren leer zurück
alex zern
1
@ AlexZern Nun, das ist einer der Gründe, warum Sie die Ausgabe von nicht analysieren ls.
Terdon
2
@AlexZern warum brauchst du den -lswitch überhaupt? Wenn Sie nur die Dateinamen möchten, führen Sie einfach aus ls -A. Das Verwenden von -lmacht Ihnen das Leben nur schwerer, da Sie jetzt die Ausgabe analysieren müssen.
Terdon
Ich benötige zusätzliche Informationen wie Zugang, Datum, Eigentümer usw. Und ich habe ein riesiges Skript geschrieben, das gut funktioniert, mit Ausnahme von Druckdatei- und Verzeichnisnamen mit Leerzeichen.
Alex Zern
3
OK dann. Was wir hier haben, ist ein XY-Problem . lsist einfach nicht der beste Weg, um das zu bekommen, was Sie brauchen. Warum posten Sie nicht eine neue Frage, in der die Informationen erläutert werden, die Sie sammeln möchten, und wir können Ihnen Möglichkeiten vorschlagen, dies zu tun. Alternativ können Sie Ihr Skript so verwenden, wie es ist, und einen der obigen Vorschläge verwenden, um nur den Namen zu drucken. Aber im Ernst, analysieren Sie nicht, sondern lssagen Sie uns genau, was Sie in einer neuen Frage versuchen.
Terdon
74

Gibt es einen Grund, warum ls -A1* nicht funktioniert?

Z.B:

$ 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
$

* Hinweis: Das ist ein Großbuchstabe A und die Nummer eins.

Bahamat
quelle
4
die -1 ist genial. Ich wusste nicht, dass verfügbar war. (Ich weiß, ich weiß. RTFM)
The Lazy Coder
das funktioniert nur für aktuelles Verzeichnis , wenn Sie Dateinamen auflisten mögen aus anderem Verzeichnis sagt ~ / Projekte dann werden Sie vollständige Pfade statt Dateinamen bekommen
thecotne
@thecotne unter Mac 10.9.5 listet nur die Dateinamen auf. Welches Betriebssystem verwenden Sie?
AJP
Ich lasse dieses ls ~ / projects / *. sublime-project -A1 für ls ~ / projects -A1 laufen. Ich erhalte nur Namen
thecotne
3
Es wird nicht erwartet, dass @TheLazyCoder das Handbuch liest.
c24w
41

Ich frage mich, warum niemand diesen einfachen Befehl erwähnt hat:

ls -a | sort
Ben
quelle
2
Brillant! Irgendeine Idee, wie sortdas Leiten zu bewirkt , dass ein mehrspaltiger Block in eine einzelne Spalte aufgehoben wird?
Msciwoj
@msciwoj es dauert nur alle Zeichenfolgen durch Leerzeichen getrennt und druckt sie sortiert nach Endzeilen getrennt
Ben
PERFEKT! Warum wurde dieser nicht als echte Antwort markiert?
夏 期 劇場
3
Dies funktioniert hier, weil die Ausgabe lsauf ls -1(einspaltige Ausgabe) zurückgesetzt wird, wenn die Ausgabe nicht an ein Terminal gesendet wird (und nicht druckbare Anführungszeichen / Ersetzungen deaktiviert werden; @Kusalananda, lswenn dies immer noch der Fall ist, sind Sie nicht POSIX-kompatibel). lsDie Ausgabe ist bereits sortiert. sortWenn Sie es also weiterleiten , wird im besten Fall nichts unternommen, und im schlimmsten Fall wird die Ausgabe beschädigt (wenn Dateinamen Zeilenumbrüche enthalten), oder bei Dateinamen, die kein Text sind, schlägt dies fehl. ls -a | catwäre besser. Oder noch besser, ls -A1wie bereits erwähnt (und weil Sie in der Regel das Ersetzen / Zitieren möchten, wenn auf einem Terminal angezeigt)
Stéphane Chazelas
1
@ StéphaneChazelas Noted. lsverhält sich anders, wenn der Ausgang kein Terminal ist.
Kusalananda
3

Sie können die Ausgabe von nicht analysieren ls, geschweige denn, ls -lweil Zeilenumbrüche genauso gültig sind wie Leerzeichen in Dateinamen. Außerdem müssen Sie Symlinks berücksichtigen, die eine Ausgabe wie haben ... foo -> bar.

Warum würden Sie -lsowieso verwenden, wenn Sie nur den Dateinamen möchten?

Mach einfach:

for file in *; do
  ...
done

Wenn Sie Punktedateien einschließen möchten (außer .und ..), abhängig von der 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
Stéphane Chazelas
quelle
1

Wie wäre es mit:

for file in * .[!.]*
do
  printf "%s\n" "$file"
done
Scrutinizer
quelle
1
ls -Al | tr -s ' ' | cut -f9- -d' '

komprimiere mehrere Leerzeichen in einzelne Leerzeichen mit tr, dann kannst du cut benutzen, um die Felder zu teilen

simpleuser
quelle
-1
ls --file *|grep ^ 

Es zeigt an, welche Dateien sich in welchem ​​Verzeichnis befinden.

Vars
quelle
Ich denke nicht, dass dies die Frage anspricht.
Jeff Schaller