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 sh
diese Shell-Befehlszeile analysieren und ausführen zu lassen.
Zur Optimierung kann manchmal auf einen Shell-Aufruf verzichtet werden, wenn cmd
keine 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 zsh
und ich habe ein setopt dotglob
in 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 zsh
beim 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, perl
dass 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/zsh
mit ["zsh", "-c", "cmd"]
als Argumenten ausgeführt wird.