Почему порядок результатов подстановочных знаков может отличаться при использовании из терминала и из Perl?

Почему порядок результатов подстановочных знаков может отличаться при использовании из терминала и из Perl?

Есть папка с кучей файлов и скрипт Perl, который выводит их список с помощью ls с подстановочным знаком, например:

#!/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. Также (какотметил(а) peterph), эта оболочка, поскольку она работает в интерактивном режиме, обычно считывает файлы конфигурации, например ~/.zshrc(если оболочка zsh), в которых некоторые настройки могут влиять на выполнение подстановки.

Например:

Моя оболочка — , и у меня в ней zshесть , поэтому: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's system()интерпретировал командную строку с помощью определенной оболочки, вы можете написать:

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

При передаче более одного аргумента perl's system()никогда не вызывает неявно оболочку, поэтому выше он разветвляет процесс, в котором он запускается /bin/zshс ["zsh", "-c", "cmd"]аргументами.

Связанный контент