ターミナルから使用した場合と perl から使用した場合でワイルドカードの結果の順序が異なるのはなぜですか?

ターミナルから使用した場合と perl から使用した場合でワイルドカードの結果の順序が異なるのはなぜですか?

多数のファイルと、次のようなワイルドカードを使用した ls を使用してそれらを一覧表示する Perl スクリプトを含むフォルダーがあります。

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

bash ターミナルからまったく同じコマンドを実行すると、結果は同じになりますが、順序が異なることに気付きました。

これはなぜでしょうか? ワイルドカードは両方のコンテキストで異なる方法で処理されますか?

例:

mkdir dir
touch dir/a_0 dir/a1_0

端末出力:

dir/a_0
dir/a1_0

perl出力:

dir/a1_0
dir/a_0

答え1

Perl のsystem("cmd")関数は通常、プロセスをフォークし、子プロセスで、 を/bin/sh引数としてシステムのシェル (通常は )を実行し、 がそのシェルのコマンド ラインを解析して実行できる["sh", "-c", "cmd"]ようにします。sh

最適化のため、スペースとタブ以外のcmdシェル メタ文字 (引用文字やグロブ文字、 など) が含まれていない場合は、シェル呼び出しを行わないことも;あり&&ますが、ここでは があるため、シェル メタ文字があります*

したがって、それはls -U -1 dir/*システムのシェルによって解釈されます。

dir/*に渡された一致するファイルのリストに展開するのはシェルなのでls、実行方法はシェルによって異なります。

ターミナルでは、通常はログインシェルを実行しますが、これは通常 ではありません/bin/sh。また、(ピーターフによって記録された~/.zshrc) の場合、そのシェルは対話的に実行されるため、通常は(シェルが の場合)のような設定ファイルを読み取りますzsh。ここで、一部の設定はグロブの実行方法に影響する可能性があります。

例えば:

私のシェルは でzshsetopt dotglobにはがあるので~/.zshrc、次のようになります。

$ echo *
.a d é f

を読まずに~/.zshrc

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

zshリストを並べ替えるときにロケールが優先されることに気づくでしょう。

$ sh -c 'echo *'
d f é

sh(私の場合は Debian ash) はロケールを尊重せず、C ロケールのように並べ替えます。

特定のシェルでコマンドラインを解釈したい場合は、次のように記述しperlます。system()

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

複数の引数が渡された場合、perlsystem()暗黙的にシェルを呼び出すことはありません。そのため、上記のように、引数として/bin/zsh実行されるプロセスをフォークします。["zsh", "-c", "cmd"]

関連情報