2009-07-14 7 views
5

Ich habe heute diese seltsame Codezeile, sie sagt mir "leer" oder "nicht leer", je nachdem, ob die CWD irgendwelche Elemente (außer . und ..) darin hat.Wie funktioniert dieser Perl-Liner, um zu prüfen, ob ein Verzeichnis leer ist?

Ich möchte wissen, wie es funktioniert, weil es für mich keinen Sinn macht.

perl -le 'print+(q=not =)[2==(()=<.* *>)].empty' 

Das Bit I in ist <.* *> interessiert. Ich verstehe nicht, wie es die Namen aller Dateien im Verzeichnis bekommt.

+0

Fühlen Sie sich frei, die Tags für etwas passender zu bearbeiten – dsm

+3

Haha, du bist so urkomisch! Ich rolle auf dem Boden und lache. Du hast Perl Line Noise genannt !!!! HAHAHAHAHAHAHAHAHAHAHA! – jrockway

+0

Nizza Vorlage für "Verschleierung des Jahres". Ich mag Perl, aber ich mag Kommentare im Perl-Code. – Boldewyn

Antwort

16

Es ist ein Golf-One-Liner. Das Flag -e bedeutet, dass der Rest der Befehlszeile als Programm ausgeführt wird. Die -l ermöglicht automatische Zeilenendeverarbeitung.

Der <.* *> Teil ist ein glob, der zwei zu erweiternde Muster enthält: .* und *.

Dieser Teil

(q=not =) 

ist eine Liste einen einzelnen Wert enthält - die Zeichenfolge "nicht". Die q=...= ist ein alternativer Zeichenfolgebegrenzer, der scheinbar verwendet wird, weil der einfache Anführungsstrich verwendet wird, um den Einzeiler zu zitieren.

Der [...] Teil ist der Index in dieser Liste. Der Wert des Index wird entweder 0 (der Wert „nicht  “) oder 1 (nichts, die als leere Zeichenkette druckt) werden in Abhängigkeit vom Ergebnis dieses Vergleichs:

2 == (()=<.* *>) 

Es gibt eine Menge los hier. Der Vergleich testet, ob der Glob eine Liste von genau zwei Items zurückgegeben hat (vermutlich . und ..), aber wie das funktioniert, ist schwierig. Die inneren Klammern bezeichnen eine leere Liste. Wenn Sie diese Liste zuweisen, wird der Glob im Listenkontext platziert, sodass alle Dateien im Verzeichnis zurückgegeben werden. (Im skalaren Kontext würde es sich wie ein Iterator verhalten und nur einen nach dem anderen zurückgeben.) Die Zuweisung selbst wird im skalaren Kontext ausgewertet (auf der rechten Seite des Vergleichs) und gibt daher die Anzahl der zugewiesenen Elemente zurück.

Die führende + ist zu verhindern, dass Perl die Liste als Argumente zu print analysieren.Das nachfolgende verknüpft die Zeichenfolge "empty" mit dem, was aus der Liste kam (d. H. Entweder "nicht  " oder die leere Zeichenfolge).

+1

+1 schöne, prägnante Erklärung – hillu

+0

Das ist ein wenig irreführend. Die innere() machen es eine Liste Zuweisung, die seinen rechten Operandenliste Kontext gibt, aber es könnte genauso gut sein (2 == (@ a = <.* *>)). – ysth

+0

@ysth: Ich bin nicht sicher, warum Sie das für irreführend halten. Da im inneren '()' nichts ist, wird die Liste verworfen. Der Zweck der Klammern (aus der Perspektive des Programmierers) bestand darin, den Listenkontext auf glob zu setzen. Er hätte stattdessen einem Array zugewiesen werden können (was IMHO klarer gewesen wäre), aber er tat es nicht. Oder beziehen Sie sich auf die Tatsache, dass die leere Zuweisung die Semantik ändert von "eine Liste im skalaren Kontext gibt das letzte Element zurück" bis "Liste Zuweisung gibt die Anzahl der Elemente zurück"? Ich sollte wahrscheinlich die Antwort bearbeiten, um dieses Bit zu klären ... –

3

<.* *> bedeutet (glob(".*"), glob("*")). glob erweitert Dateimuster auf die gleiche Weise wie die Shell.

7
<.* *> 

ist ein glob von zwei Mustern aus: .* sind alle Dateinamen, die mit . beginnen und * entsprechen alle Dateien (dies ist anders als die übliche DOS/Windows-Konventionen).

(()=<.* *>) 

wertet den Glob im Listenkontext aus und gibt alle übereinstimmenden Dateinamen zurück.

Dann vergleicht der Vergleich mit 2 es in skalaren Kontext, so 2 wird mit der Anzahl der zurückgegebenen Dateien verglichen. Wenn diese Nummer 2 ist, sind die einzigen Verzeichniseinträge . und .., Punkt. ;-)

0

Die Dokumentation für dieses Feature lautet here. (Blättern Sie in der Nähe des Endes des Abschnitts)

+2

Welche Funktion? Soll das ein Kommentar zu jemandes Antwort sein? – Telemachus

+0

@Telemachus: <> meinen, vermutlich, glob. – ysth

+0

@Telemachus: Die Dokumentation für den glob/<>, wie @ysth – dsm

2

Ich finde, dass das B::Deparse Modul hilft ziemlich viel in ein paar Sachen zu entziffern, die meisten Programmierer Augen, wie das q=...= Konstrukt abwirft:

$ perl -MO=Deparse,-p,-q,-sC 2>/dev/null << EOF 
> print+(q=not =)[2==(()=<.* *>)].empty 
> EOF 
use File::Glob(); 
print((('not ')[(2 == (() = glob('.* *')))] . 'empty')); 

Natürlich , das erzeugt nicht sofort "lesbaren" Code, aber es konvertiert sicher einige der Stolpersteine.

+0

Heh. Keine Menge von De-Parsing wird die Verwendung eines booleschen Indexes zum Indexieren in eine anonyme Liste ent-verschleiern. [Anti-Pedanterie: Ja, ich weiß, dass "anonyme Liste" überflüssig ist.] –