Warum kann die Reihenfolge der Platzhalterergebnisse unterschiedlich sein, wenn sie vom Terminal oder von Perl aus verwendet werden?

Warum kann die Reihenfolge der Platzhalterergebnisse unterschiedlich sein, wenn sie vom Terminal oder von Perl aus verwendet werden?

Es gibt einen Ordner mit einer Reihe von Dateien und ein Perl-Skript, das sie auflistet. Dabei wird „ls“ mit einem Platzhalterzeichen verwendet, etwa so:

#!/usr/bin/perl
system("ls -U -1 dir/*");

Mir ist aufgefallen, dass ich dieselben Ergebnisse erhalte, wenn ich genau denselben Befehl von meinem Bash-Terminal aus ausführe, allerdings in einer anderen Reihenfolge.

Woran kann das liegen? Wird das Platzhalterzeichen in beiden Kontexten unterschiedlich behandelt?

Beispiel:

mkdir dir
touch dir/a_0 dir/a1_0

Terminalausgabe:

dir/a_0
dir/a1_0

Perl-Ausgabe:

dir/a1_0
dir/a_0

Antwort1

Die Perl- system("cmd")Funktion verzweigt normalerweise einen Prozess und führt im untergeordneten Prozess die Shell des Systems (normalerweise /bin/sh) mit als Argumenten aus, ["sh", "-c", "cmd"]um shdiese Shell-Befehlszeile analysieren und ausführen zu lassen.

Zur Optimierung kann manchmal auf einen Shell-Aufruf verzichtet werden, wenn cmdkeine Shell-Metazeichen (wie Anführungszeichen oder Globbing-Zeichen oder Dinge wie ;, &&...) außer Leerzeichen und Tabulatoren enthalten sind, hier haben wir aber Shell-Metazeichen, da wir ein haben *.

ls -U -1 dir/*Dies wird also von der Shell des Systems interpretiert.

Es ist die Shell, die dir/*zu einer Liste übereinstimmender Dateien erweitert wird ls, die an übergeben werden. Die Art und Weise, wie dies geschieht, hängt also von der Shell ab.

In einem Terminal führen Sie normalerweise Ihre Login-Shell aus, die im Allgemeinen nicht ist /bin/sh. Außerdem (wienotiert von peterph), diese Shell wird, da sie interaktiv ausgeführt wird, normalerweise Konfigurationsdateien wie lesen ~/.zshrc(wenn die Shell zsh) wobei einige Einstellungen die Art und Weise beeinflussen können, wie das Globbing durchgeführt wird.

Zum Beispiel:

Meine Shell ist zshund ich habe ein setopt dotglobin meinem ~/.zshrc, also:

$ echo *
.a d é f

Ohne das zu lesen ~/.zshrc:

$ zsh -c 'echo *'
d é f
$ LC_ALL=C zsh -c 'echo *'
d f é

Sie werden feststellen, dass zshbeim Sortieren der Liste das Gebietsschema berücksichtigt wird.

$ sh -c 'echo *'
d f é

sh(in meinem Fall Debian ash) berücksichtigt das Gebietsschema nicht und sortiert, als ob es sich im Gebietsschema C befände.

Wenn Sie möchten, perldass system()die Befehlszeile mit einer bestimmten Shell interpretiert wird, können Sie Folgendes schreiben:

system("zsh", "-c", "cmd");

Wenn mehr als ein Argument übergeben wird, ruft perl's system()niemals implizit eine Shell auf. Oben verzweigt es sich daher in einen Prozess, in dem es /bin/zshmit ["zsh", "-c", "cmd"]als Argumenten ausgeführt wird.

verwandte Informationen