it-swarm.com.de

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

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

86
Andy M

ls listet die Dateien und den Inhalt der Verzeichnisse auf, die als Argumente übergeben werden. 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 (Einzelheiten finden Sie unter man ls).

Wenn ls ein 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. ls behandelt das Zeichen * Nicht anders als jedes andere.

Wenn ls * Eine Shell-Befehlszeile ist, erweitert die Shell diese * Entsprechend der entsprechenden Shell = globbing (auch als Dateinamengenerierung bezeichnet oder Dateinamenerweiterung) Regeln.

Während verschiedene Shells verschiedene Globbing-Operatoren unterstützen, stimmen die meisten von ihnen dem einfachsten zu *. * Als Muster bedeutet eine beliebige Anzahl von Zeichen, daher wird * Als glob auf die Liste der Dateien in den aktuellen Verzeichnissen erweitert, die diesem Muster entsprechen. Es gibt jedoch eine Ausnahme, dass ein führendes Punktzeichen (.) In einem Dateinamen explizit übereinstimmen muss, sodass * Tatsächlich auf die Liste der Dateien und Verzeichnisse erweitert wird, die nicht mit . (in lexikographischer Reihenfolge).

Wenn das aktuelle Verzeichnis beispielsweise die Dateien ., .., .foo, -l Und foo bar Enthält, * wird von der Shell auf zwei Argumente erweitert, die an ls übergeben werden sollen: -l und foo bar. Es ist also so, als hätten Sie Folgendes eingegeben:

ls -l "foo bar"

oder

'ls' "-l" foo\ bar

Welches sind drei Möglichkeiten, um genau den gleichen Befehl auszuführen. In allen drei Fällen wird dem Befehl ls (der wahrscheinlich von /bin/ls Aus einer Suche nach in $PATH Erwähnten Verzeichnissen ausgeführt wird) die folgenden drei Argumente übergeben: "ls" , "-l" und "foo bar".

Übrigens wird in diesem Fall ls den ersten (genau genommen zweiter) als Option behandeln.

Nun, wie gesagt, verschiedene Shells haben unterschiedliche Globbing-Operatoren. Vor einigen Jahrzehnten hat zsh den Operator **/ 1 eingeführt, der bedeutet, dass alle Ebenen von Unterverzeichnissen abgeglichen werden, kurz für (*/)# Und ***/, Die bis auf das gleiche identisch sind Es folgt Symlinks beim Absteigen der Verzeichnisse.

Vor einigen Jahren (Juli 2003, ksh93o+) Hat ksh93 Beschlossen, dieses Verhalten zu kopieren, es jedoch optional zu machen, und nur den Fall ** Behandelt (nicht ***). Auch wenn ** In zsh ² allein nichts Besonderes war (bedeutet nur dasselbe wie * Wie in anderen traditionellen Shells, da ** Eine beliebige Anzahl von Zeichen bedeutet gefolgt von einer beliebigen Anzahl von Zeichen) bedeutete in $ ksh93 ** dasselbe wie **/* (also jede Datei oder jedes Verzeichnis unter dem aktuellen (ausgenommen versteckte Dateien).

bash kopierte ksh93 Einige Jahre später (Februar 2009, Bash 4.0) mit derselben Syntax, aber einem unglücklichen Unterschied: Bashs ** War wie zsh ' s ***, das heißt, es wurden Symlinks beim Rekursieren in Unterverzeichnisse verfolgt, was im Allgemeinen nicht das ist, was Sie möchten, und böse Nebenwirkungen haben kann. Es wurde teilweise in Bash-4.3 behoben, indem Symlinks weiterhin befolgt wurden, aber die Rekursion dort gestoppt wurde. Es wurde vollständig in 5.0 behoben.

yash hat 2008 ** In Version 2.0 hinzugefügt und mit der Option extended-glob Aktiviert. Die Implementierung ist näher an der von zsh, da ** Allein nichts Besonderes ist. In Version 2.15 (2009) wurden *** Wie in zsh und zwei eigene Erweiterungen hinzugefügt: .** Und .***, Um versteckte Verzeichnisse beim Rekursieren einzuschließen ( In zsh berücksichtigt das D glob-Qualifikationsmerkmal (wie in **/*(D)) versteckte Dateien und Verzeichnisse, aber wenn Sie nur möchten Wenn Sie versteckte Verzeichnisse durchlaufen, aber keine versteckten Dateien erweitern, benötigen Sie ((*|.*)/)#* oder **/[^.]*(D)).

Die Fischschale unterstützt auch **. Wie in der früheren Version von bash folgt es beim Absteigen des Verzeichnisbaums Symlinks. In dieser Shell ist **/* Jedoch nicht dasselbe wie **. ** Ist eher eine Erweiterung von *, Die mehrere Verzeichnisse umfassen kann. In fish stimmt **/*.c Mit a/b/c.c, Nicht jedoch mit a.c Ab, während a**.c Mit a.c Und ab/c/d.c Und zsh**/.* Müssen zum Beispiel .* **/.* Geschrieben werden. Dort wird *** Als ** Verfolgt, gefolgt von *, Also dasselbe wie **.

tcsh hat in V6.17.01 (Mai 2010) auch eine Option globstar hinzugefügt und unterstützt sowohl ** Als auch *** À la zsh.

Also in tcsh, bash und ksh93 (Wenn die entsprechende Option aktiviert ist (globstar)) oder fish, ** Erweitert alle Dateien und Verzeichnisse unter dem aktuellen und *** Ist dasselbe wie ** Für fish, ein Symlink, der ** Für tcsh mit globstar und dasselbe wie * In bash und ksh93 (Obwohl es nicht unmöglich ist, dass zukünftige Versionen dieser Shells dies auch tun Traverse-Symlinks).

Oben haben Sie bemerkt, dass Sie sicherstellen müssen, dass keine der Erweiterungen als Option interpretiert wird. Dafür würden Sie tun:

ls -- *

Oder:

ls ./*

Es gibt einige Befehle (für ls spielt es keine Rolle), bei denen der zweite vorzuziehen ist, da selbst mit -- Einige Dateinamen möglicherweise speziell behandelt werden. Dies ist der Fall bei - Für die meisten Textdienstprogramme, cd und pushd sowie bei Dateinamen, die beispielsweise das Zeichen = Für awk enthalten. Wenn Sie allen Argumenten ./ Voranstellen, wird ihre besondere Bedeutung entfernt (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 $FIGNORE In ksh

Auch in jeder Shell außer csh, tcsh, fish und zsh, wenn das Globbing-Muster dies nicht tut Bei jeder Datei wird das Muster als nicht erweitertes Argument übergeben, das Verwirrung und möglicherweise Fehler verursacht. Zum Beispiel, wenn sich im aktuellen Verzeichnis keine nicht versteckte Datei befindet

ls *

Ruft tatsächlich ls mit den beiden Argumenten ls und * Auf. Und da es überhaupt keine Datei gibt, also auch keine mit dem Namen *, Wird eine Fehlermeldung von ls (nicht von der Shell) angezeigt ) wie: ls: cannot access *: No such file or directory, von dem bekannt ist, dass es die Leute glauben lässt, dass es ls war, das die Globs tatsächlich erweitert hat.

Das Problem ist noch schlimmer in Fällen wie:

rm -- *.[ab]

Wenn sich im aktuellen Verzeichnis keine Datei *.a Noch *.b Befindet, wird möglicherweise versehentlich eine Datei mit dem Namen *.[ab] Gelöscht (csh, tcsh und zsh würden einen keine Übereinstimmung Fehler melden und würden rm nicht aufrufen (und fish unterstützt das nicht [...] Platzhalter)).

Wenn Sie ein Literal * An ls übergeben möchten, müssen Sie dieses * - Zeichen wie in ls \* Oder ls '*' oder ls "*". In POSIX-ähnlichen Shells kann das Globbing mit set -o noglob Oder set -f Vollständig deaktiviert werden (letzteres funktioniert nicht in zsh, außer in sh/ksh Emulation).


¹ Während (*/)# Immer unterstützt wurde, wurde es zuerst als ..../ In zsh-2.0 (und möglicherweise vorher), dann als ****/ In 2.1 unterboten, bevor es seine endgültige Form erhielt **/ In 2.2 (Anfang 1992)

² Die Option globstarshort wurde seitdem (im Jahr 2015) hinzugefügt, damit ** Und *** Anstelle von **/* Verwendet werden können. bzw. ***/*

156

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

Der Befehl ls * Bedeutet "Ls bei der Erweiterung des Shell-Musters * Ausführen".

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

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

* Ist ein Platzhalter, der 0 oder mehr Zeichen entspricht. Einige moderne Shells werden beim Anzeigen des Musters ** In Unterverzeichnisse zurückgeführt.

36

Sie können den gesamten Prozess entmystifizieren, indem Sie zuerst echo anstelle von ls eingeben, um zu sehen, auf was der Befehl erweitert wird:

$ echo *
Applications Downloads Documents tmp.html

In diesem Fall wird ls * Auf ls Applications Downloads Documents tmp.html Erweitert.

$ echo **
Applications Downloads Documents tmp.html

$ echo ***
Applications Downloads Documents tmp.html

Also keine Veränderung. Dies setzt voraus, dass Sie bash als Shell verwenden - die meisten Menschen sind es und verschiedene Shells haben ein unterschiedliches Verhalten. Wenn Sie ash oder csh oder ksh oder zsh verwenden, können Sie erwarten, dass die Dinge anders funktionieren. Das ist der Punkt, verschiedene Muscheln zu haben.

Versuchen wir also etwas anderes (immer noch mit bash), 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. */ Liefert also 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 Verzeichnis Downloads keine Unterverzeichnisse enthält, landet es nicht in der Ausgabe. Dies ist sehr nützlich, um nur die gewünschten Dateien zu untersuchen. Ich benutze ständig solche Befehle:

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

Hier werden, falls vorhanden, alle wp-config.php - Dateien aufgelistet, die auf der Basisebene des public_html - Verzeichnisses eines Benutzers vorhanden sind. Oder vielleicht um vollständiger zu sein:

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

Dadurch werden alle wp-config.php - Dateien in den public_html - Verzeichnissen eines Benutzers oder in einem seiner Unterverzeichnisse gefunden, aber es arbeitet effizienter als nur find /home/ -name wp-config.php, Da nichts untersucht wird - aber die public_html - Verzeichnisse für jeden Benutzer.

12
tylerl

In einigen Shells, einschließlich Bash 4.x mit aktivierter Option globstar, ** führt einen rekursiven Glob mit absteigenden übereinstimmenden Verzeichnissen durch. Zusätzliche Sternchen ändern diesen Vorgang nicht weiter.

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

find . -ls

"find" taucht am Ende des Verzeichnisbaums ab (ebenso wie '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 Eigenschaften (kein Benutzer in/etc/passwd, bestimmte Berechtigungen und vieles mehr). "find" ist auch beim Scripting etwas sicherer (aufgrund inkonsistenter Globbing-Regeln zwischen Shells sowie spezieller Escape-Zeichen für Dateien mit Bindestrichen usw.).

Das Globbing von Shell-Wildcards funktioniert nicht nur mit einem Sternchen '*' auf Punktedateien. Verwenden Sie Folgendes, um nur Punktdateien aufzulisten:

ls .??*

0
Razzlephrazz