Das Ergebnis von ls *, ls ** und ls ***

86

Ich weiß, dass mit dem Befehl lsalle Verzeichnisse aufgelistet werden. Aber was macht der ls *Befehl? Ich habe es benutzt und es listet nur die Verzeichnisse auf. Bedeutet der Stern vor ls, wie tief er die Verzeichnisse auflisten kann?

Andy M
quelle

Antworten:

155

lsListet die Dateien und den Inhalt der Verzeichnisse, die als Argumente übergeben werden, auf. Wenn kein Argument angegeben wird, wird das aktuelle Verzeichnis aufgelistet. Es können auch eine Reihe von Optionen übergeben werden, die sich auf das Verhalten auswirken ( man lsDetails siehe ).

Wenn lsein Argument mit dem Namen übergeben *wird, sucht es *im aktuellen Verzeichnis nach einer Datei oder einem Verzeichnis mit dem Namen und listet es wie jedes andere auf. lsbehandelt den *Charakter nicht anders als irgendeinen anderen.

Wenn ls *es sich jedoch um eine Shell- Befehlszeile handelt, wird die Shell *entsprechend den Globbing- Regeln der entsprechenden Shell (auch als Dateinamengenerierung oder Dateinamenerweiterung bezeichnet ) erweitert.

Während verschiedene Shells verschiedene Globbing-Operatoren unterstützen, stimmen die meisten mit dem einfachsten überein *. *als Muster bedeutet , eine beliebige Anzahl von Zeichen, so *wie ein globin der Liste der Dateien in den aktuellen Verzeichnissen zu erweitern, die dieses Muster passen. Es gibt jedoch eine Ausnahme, dass ein führendes Punkt ( .) in einem Dateinamen explizit abgeglichen werden muss, sodass *die Liste der Dateien und Verzeichnisse, die nicht mit .(in lexikografischer Reihenfolge) beginnen, erweitert wird.

Zum Beispiel, wenn das aktuelle Verzeichnis die Dateien mit dem Namen enthält ., .., .foo, -lund foo bar, *wird von der Shell auf zwei Argumente erweitert werden , um zu übergeben ls: -lund foo bar, so es wie sein wird , wenn Sie eingegeben haben:

ls -l "foo bar"

oder

'ls' "-l" foo\ bar

Mit diesen drei Methoden können Sie genau den gleichen Befehl ausführen. In allen drei Fällen werden dem lsBefehl (der wahrscheinlich /bin/lsvon einem Verzeichnis aus ausgeführt wird, in dem nachgeschlagen wird $PATH) diese drei Argumente übergeben: "ls", "-l" und "foo bar".

Im Übrigen wird in diesem Fall lsder erste (genau genommen der zweite ) als Option behandelt.

Wie ich bereits sagte, haben verschiedene Shells unterschiedliche Globbing-Operatoren. Vor einigen Jahrzehnten wurde zshder **/Operator¹ eingeführt , der bedeutet, dass er mit jeder Ebene von Unterverzeichnissen übereinstimmt, kurz für (*/)#und ***/mit der Ausnahme, dass er Symlinks folgt, während er die Verzeichnisse absteigt.

Vor ein paar Jahren (Juli 2003 ksh93o+) ksh93entschied man sich, dieses Verhalten zu kopieren, entschied sich jedoch dafür, es optional zu machen, und deckte nur den **Fall ab (nicht ***). Auch während **alleine nichts Besonderes war zsh(nur dasselbe gemeint *wie in anderen traditionellen Shells, da **bedeutet, dass eine beliebige Anzahl von Zeichen gefolgt von einer beliebigen Anzahl von Zeichen), **bedeutete ksh93 dasselbe wie **/*(also jede Datei oder jedes Verzeichnis unterhalb der aktuellen) (ausgenommen versteckte Dateien).

bashksh93Einige Jahre später kopiert (Februar 2009, Bash 4.0), mit der gleichen Syntax, aber mit einem unglücklichen Unterschied: Bash **war wie zsh's ***, dh es folgten Symlinks, wenn Sie in Unterverzeichnisse zurückkehren, was im Allgemeinen nicht das ist, was Sie wollen und tun kann böse Nebenwirkungen haben. Es wurde teilweise in Bash-4.3 behoben, dass Symlinks weiterhin verfolgt wurden, aber die Rekursion dort aufhörte. Es wurde in 5.0 vollständig behoben.

yashhinzugefügt **in Version 2.0 im Jahr 2008, aktiviert mit der extended-globOption. Seine Implementierung ist näher zshdran, das **allein ist nichts Besonderes. In Version 2.15 (2009) wurden ***like in zshund zwei eigene Erweiterungen hinzugefügt : .**und .***um verborgene Verzeichnisse bei der Rekursion einzuschließen ( in ), berücksichtigt zshdas D Qualifikationsmerkmal glob (wie in **/*(D)) verborgene Dateien und Verzeichnisse, wenn Sie jedoch nur verborgene Verzeichnisse durchlaufen möchten Verzeichnisse, aber versteckte Dateien nicht erweitern, benötigen Sie ((*|.*)/)#*oder **/[^.]*(D)).

Die Fischschale unterstützt auch **. Wie in früheren Versionen von bashfolgt es Symlinks beim Abstieg in den Verzeichnisbaum. In dieser Shell ist jedoch **/*nicht das gleiche wie **. **ist eher eine Erweiterung *, die sich über mehrere Verzeichnisse erstrecken kann. In fish, **/*.cwird passen , a/b/c.caber nicht a.c, während a**.cpasst auf a.cund ab/c/d.cund zshist **/.*zum Beispiel hat geschrieben werden .* **/.*. Dort ***wird verstanden wie **gefolgt von *so dasselbe wie **.

tcshfügte auch eine globstarOption in V6.17.01 (Mai 2010) hinzu und unterstützt sowohl **als auch ***à la zsh.

So in tcsh, bashund ksh93, (wenn die entsprechende Option aktiviert ist ( globstar)) oder fish, **erweitert um alle Dateien und Verzeichnisse unterhalb des aktuellen, und ***ist die gleiche wie **für fisheine Symlink überquert **für tcshmit globstar, und das gleiche wie *in bashund ksh93(obwohl es Es ist nicht unmöglich, dass zukünftige Versionen dieser Shells auch Symlinks durchlaufen werden.

Oben haben Sie die Notwendigkeit bemerkt, sicherzustellen, dass keine der Erweiterungen als Option interpretiert wird. Dafür würden Sie Folgendes tun:

ls -- *

Oder:

ls ./*

Es gibt einige Befehle (es spielt keine Rolle ls), bei denen der zweite vorzuziehen ist, da selbst bei --einigen Dateinamen eine spezielle Behandlung möglich ist. Es ist der Fall -für die meisten Texte Dienstprogramme, cdund pushdund Dateinamen , die die enthaltenen =Zeichen für awkzum Beispiel. Das Voranstellen ./aller Argumente beseitigt ihre besondere Bedeutung (zumindest für die oben genannten Fälle).

Es sollte auch beachtet werden, dass die meisten Shells eine Reihe von Optionen haben, die das Globbing-Verhalten beeinflussen (z. B. ob Punktdateien ignoriert werden oder nicht, die Sortierreihenfolge, was zu tun ist, wenn keine Übereinstimmung vorliegt ...), siehe auch den $FIGNOREParameter inksh

Auch in jeder Schale aber csh, tcsh, fishund zsh, wenn das Globbing Muster keine Datei übereinstimmt, wird das Muster als nicht expandierten Argument übergeben , die Verwirrung und möglicherweise Fehler verursacht. Zum Beispiel, wenn sich im aktuellen Verzeichnis keine nicht ausgeblendete Datei befindet

ls *

Werde eigentlich lsmit den beiden Argumenten lsund anrufen *. Und da es überhaupt keine Datei ist, so dass keiner genannt *entweder, erhalten Sie eine Fehlermeldung aus sehen ls (nicht die Shell) wie: ls: cannot access *: No such file or directory, die bekannt ist Menschen zu denken , dass es war , lsdass tatsächlich wurde die Kleckse zu erweitern.

Das Problem ist noch schlimmer in Fällen wie:

rm -- *.[ab]

Wenn es keine gibt , *.anoch *.bim aktuellen Verzeichnis - Datei, dann könnten Sie eine Datei namens Löschen am Ende *.[ab]versehentlich ( csh, tcshund zshwürde einen Bericht keine Übereinstimmung Fehler und würde nicht nennen rm(und fishunterstützt nicht die [...]Platzhalter)).

Wenn Sie eine wörtliche passieren wollen *zu ls, haben Sie das zitieren *Charakter in irgendeiner Weise wie in ls \*oder ls '*'oder ls "*". In POSIX-ähnlichen Shells kann das Globbing mit set -o nogloboder deaktiviert werden set -f(letzteres funktioniert nur zshin sh/ kshemulation).


¹ Während (*/)#es immer unterstützt wurde, war es zuerst wie ..../in zsh-2.0 (und möglicherweise vorher), dann ****/in 2.1, bevor es seine endgültige Form **/in 2.2 bekam (Anfang 1992).

Stéphane Chazelas
quelle
22
Wirklich tolle Antwort!
Andrea Corbellini
7
Ein weiteres schönes Beispiel ist find -name *. Insbesondere bei komplexeren Mustern werden die Benutzer häufig nicht bemerken, dass genau eine Übereinstimmung im aktuellen Verzeichnis vorliegt, an die sie den Stern nicht weitergeben find.
NJSG
Ich gebe weiterhin +1 und freue mich sehr, dass Stephane Chazelas hier auf unix.stackexchange.com aktiv ist ! Tolle Beiträge, Stephane, wie immer!
Dimitre Radoulov
1
Bei Fischen *.[ab]würde versucht, alles zu löschen, was mit endet .[ab]. [ist nichts Besonderes in Fisch.
Konrad Borowski
35

Der Befehl lslautet standardmäßig ls .: Alle Einträge im aktuellen Verzeichnis auflisten .

Der Befehl ls *bedeutet 'ls auf die Erweiterung des *Shell-Musters ausführen '

Das *Muster wird von der Shell verarbeitet und auf alle Einträge im aktuellen Verzeichnis erweitert, mit Ausnahme der Einträge, die mit einem beginnen .. Es wird eine Ebene tiefer gehen.

Die Interpretation von Doppel- oder Dreifachmustern *hängt von der tatsächlich verwendeten Schale ab.

*ist ein Platzhalter, der 0 oder mehr Zeichen entspricht. Einige moderne Shells werden beim Anzeigen des **Musters wieder in Unterverzeichnisse verschoben .

Dennis Kaarsemaker
quelle
17
Abgesehen davon, dass * Sie etwas hinzufügen müssen, finden Sie in der anderen Antwort eine Erklärung für den Globstar. Es sollte auch klargestellt werden, dass ls nichts mit den Sternchen zu tun hat, es hat keines dieser Sternchen bestanden. Führen echo ls *Sie den Befehl aus, um zu sehen, was beim Schreiben ausgeführt wird ls *.
NJSG
12

Sie können den gesamten Prozess entmystifizieren, indem Sie echostatt lszuerst Folgendes eingeben , um zu sehen, zu was der Befehl erweitert wird:

$ echo *
Applications Downloads Documents tmp.html

Also in diesem Fall ls *erweitertls Applications Downloads Documents tmp.html

$ echo **
Applications Downloads Documents tmp.html

$ echo ***
Applications Downloads Documents tmp.html

Also keine Veränderung. Dies setzt voraus, dass Sie bashals Shell verwenden - die meisten Menschen sind es und verschiedene Shells haben ein unterschiedliches Verhalten. Wenn Sie ashoder cshoder kshoder verwenden zsh, können Sie davon ausgehen, dass die Dinge anders funktionieren. Das ist der Punkt, wenn man verschiedene Muscheln hat.

Versuchen bashwir also etwas anderes (immer noch mit ), damit wir eine Vorstellung davon bekommen, was der globbing ( *) -Operator für uns tun kann. Zum Beispiel können wir nach einem Teil des Namens filtern:

$ echo D*
Downloads Documents

Interessanterweise ist ein abschließender Schrägstrich ein impliziter Bestandteil jedes Verzeichnisnamens. So */ergeben sich nur die Verzeichnisse (und symbolische Links zu Verzeichnissen):

$ echo */
Applications/ Downloads/ Documents/

Und wir können auf mehreren Ebenen filtern, indem wir Schrägstriche in die Mitte setzen:

$ echo D*/*/
Documents/Work/ /Documents/unfinished/

Da das DownloadsVerzeichnis keine Unterverzeichnisse enthält, wird es nicht in der Ausgabe ausgegeben. Dies ist sehr nützlich, um nur die gewünschten Dateien zu untersuchen. Ich benutze immer solche Befehle:

$ ls -l /home/*/public_html/wp-config.php

Hier werden, falls vorhanden, alle wp-config.phpDateien aufgelistet, die auf der Basisebene eines Benutzerverzeichnisses vorhanden sind public_html. Oder vielleicht um vollständiger zu sein:

$ find /home/*/public_html/ -name wp-config.php

Auf diese Weise werden alle wp-config.phpDateien in den public_htmlVerzeichnissen eines Benutzers oder in einem seiner Unterverzeichnisse gefunden. Sie werden jedoch effizienter ausgeführt, als nur, find /home/ -name wp-config.phpweil nur die public_htmlVerzeichnisse der einzelnen Benutzer überprüft werden.

tylerl
quelle
1
"Dies setzt voraus, dass Sie bashals Shell verwenden" ← und dass der Globstar nicht aktiviert ist. shopt -s globstarund versuchen Sie es erneut ...
NJSG
Eine andere Möglichkeit zum Entmystifizieren besteht darin set -x, den "tatsächlichen" Befehl zu drucken, der jedes Mal ausgeführt wird (Ausschalten mit set +x).
ShreevatsaR
10

In einigen Shells, einschließlich Bash 4.x mit globstaraktivierter Option, **wird ein rekursiver Glob ausgeführt, der absteigende übereinstimmende Verzeichnisse enthält. Zusätzliche Sternchen ändern diesen Vorgang nicht weiter.

Ignacio Vazquez-Abrams
quelle
1
Obwohl , wie ich in meiner Antwort sagte, passen sie, dass im Gegensatz zu ksh93und zsh, bashtut Traverse Symlinks in der Rekursion , die im allgemeinen unerwünscht ist.
Stéphane Chazelas
Das wurde in Bash 4.3
Stéphane Chazelas,
1

Wenn Sie tief tauchen möchten, verwenden Sie die Option ls -R (rekursiv) oder verwenden Sie find wie folgt:

find . -ls

"find" taucht bis zum Ende des Verzeichnisbaums auf (wie auch "ls -R") und bietet viele weitere Optionen, z. B. das Auflisten von Verzeichnissen (-type d), nur Dateien (-type f) oder das Anzeigen von Dateien mit anderen Merkmale (kein Benutzer in / etc / passwd, bestimmte Berechtigungen und vieles mehr). "find" ist auch etwas sicherer bei der Skripterstellung (aufgrund inkonsistenter Globbing-Regeln zwischen Shells sowie spezieller Escapes für Dateien mit Bindestrichen usw.).

Shell-Platzhalter-Globbing funktioniert bei Punktdateien nicht nur mit einem Sternchen '*'. Um nur Punktedateien aufzulisten, verwenden Sie:

ls .??*

Razzlephrazz
quelle
-1

Extra * fügt keine Tiefenstufe hinzu. Aber wenn du es versuchst

 ls */*/*

- Sie erhalten eine Liste der Unterordner von Unterordnern in Ordnern im aktuellen Ordner ...

VB9-UANIC
quelle
Falsch. Abhängig von der Muschel erhöhen zusätzliche *s die Tiefe.
NJSG
Welche Muschel verleiht zusätzlichen Sternen mehr Tiefe?
VB9-UANIC
Mehrere. Einschließlich GNU bashmit der Globstar-Option, der Korn-Shell und zsh. Und vielleicht noch andere, würde ich raten. unix.stackexchange.com/a/62665/14831
njsg
-1

Mein Hauptgriff ist, dass Echo ** / *. Ext im Allgemeinen ...

Mai oder Mai nicht: Listet eine .ext-Datei im aktuellen Verzeichnis auf

Mai oder Mai nicht:. *. Ext-Dateien einschließen

Im Allgemeinen würde ich es vorziehen, wenn der Glob-Ausdruck '** /' ist und eine leere Zeichenfolge (kein Unterverzeichnis) ergibt. So konvertiere ich Glob-Ausdrücke in Programmeingaben. Natürlich versichere ich, dass es Kommentare gibt, die dies in Anwendungsbeispielen erklären.

anthony
quelle