ワイルドカードを使用した結果の順序がターミナルや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

真珠出力:

dir/a1_0
dir/a_0

答え1

Perlsystem("cmd")機能は通常、プロセスを分岐し、サブプロセスでシステムのシェル(通常はシェル)を実行し、そのシェルを解析して実行するコマンドラインを/bin/sh引数として使用します。["sh", "-c", "cmd"]sh

最適化として、スペースやタブ以外のcmdシェルメタ文字(引用符やワイルドカード文字など)が含まれていない場合は、シェル呼び出しは不要ですが、これには;シェルメタ文字があります。&&- 文字があるので*

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

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

端末では通常ログインシェルを実行しますが、通常はそうではありません/bin/shPetervが指摘した。)、シェルは対話的に実行されるため、通常は構成ファイルを読み込みます。たとえば~/.zshrc(シェルzsh)、一部の設定はワイルドカードの完成方法に影響を与える可能性があります。

たとえば、

私のシェルはzsh次のとおりです。私のシェルには1つあります。setopt 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");

perlsは複数の引数を渡すときにsystem()暗黙的にシェルを呼び出さないため、上記のプロセスはプロセスを分岐し、そのプロセスで引数/bin/zshとして["zsh", "-c", "cmd"]実行します。

関連情報