Por que a ordem dos resultados curinga pode ser diferente quando usado no terminal ou no Perl?

Por que a ordem dos resultados curinga pode ser diferente quando usado no terminal ou no Perl?

Há uma pasta com vários arquivos e um script perl que os lista usando ls com um curinga como:

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

Percebi que se eu executar exatamente o mesmo comando em meu terminal bash, obterei os mesmos resultados, mas eles estarão em uma ordem diferente.

Por que isso pode acontecer? O curinga é tratado de maneira diferente em ambos os contextos?

Exemplo:

mkdir dir
touch dir/a_0 dir/a1_0

saída terminal:

dir/a_0
dir/a1_0

saída perl:

dir/a1_0
dir/a_0

Responder1

A função do Perl system("cmd")normalmente bifurca um processo e, no processo filho, executa o shell do sistema (normalmente /bin/sh) com argumentos, ["sh", "-c", "cmd"], para shanalisar e executar essa linha de comando do shell.

Como uma otimização, às vezes pode funcionar sem uma chamada de shell, se cmdnão contiver nenhum metacaractere de shell (como caracteres de citação ou caracteres globulares ou coisas como ;, &&...) além de espaço e tabulação, mas aqui temos shell meta -personagens, já que temos um arquivo *.

Então, isso ls -U -1 dir/*será interpretado pelo shell do sistema.

É o shell que se expande dir/*para uma lista de arquivos correspondentes passados ​​para ls, portanto, a forma como isso é feito depende do shell.

Em um terminal, você normalmente executa seu shell de login, que geralmente não é /bin/sh. Tambem comoanotado por Pedro), esse shell, uma vez que é executado de forma interativa, normalmente lerá arquivos de configuração como ~/.zshrc(se o shell for zsh), onde algumas configurações podem afetar o modo como o globbing é feito.

Por exemplo:

Meu shell é zsh, e eu tenho um setopt dotglobno meu ~/.zshrc, então:

$ echo *
.a d é f

Sem ler o ~/.zshrc:

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

Você notará que isso zshrespeita a localidade ao classificar a lista.

$ sh -c 'echo *'
d f é

sh(que no meu caso é Debian ash) não respeita a localidade e classifica como se estivesse na localidade C.

Se você quiser perlinterpretar system()a linha de comando com um shell específico, você pode escrevê-lo:

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

Quando passado mais de um argumento, perl's system()nunca chama implicitamente um shell; portanto, acima, ele bifurca um processo no qual é executado /bin/zshcom ["zsh", "-c", "cmd"]argumentos.

informação relacionada