Hay una carpeta con un montón de archivos y un script de Perl que los enumera usando ls con un comodín como:
#!/usr/bin/perl
system("ls -U -1 dir/*");
Me di cuenta de que si ejecuto exactamente el mismo comando desde mi terminal bash, obtendré los mismos resultados pero en un orden diferente.
¿Por qué podría ser esto? ¿El comodín se maneja de manera diferente en ambos contextos?
Ejemplo:
mkdir dir
touch dir/a_0 dir/a1_0
salida terminal:
dir/a_0
dir/a1_0
salida de perl:
dir/a1_0
dir/a_0
Respuesta1
La función de Perl system("cmd")
normalmente bifurca un proceso y, en el proceso hijo, ejecuta el shell del sistema (normalmente /bin/sh
) con argumentos, ["sh", "-c", "cmd"]
para sh
analizar y ejecutar esa línea de comando del shell.
Como optimización, a veces puede funcionar sin una llamada de shell, si cmd
no contiene metacaracteres de shell (como caracteres entre comillas o caracteres globales o cosas como ;
, &&
...) aparte del espacio y la tabulación, pero aquí tenemos meta de shell -caracteres ya que tenemos un *
.
Entonces, eso ls -U -1 dir/*
será interpretado por el shell del sistema.
Es el shell el que se expande dir/*
a una lista de archivos coincidentes pasados a ls
, por lo que la forma en que se hace depende del shell.
En una terminal, normalmente ejecuta su shell de inicio de sesión, que generalmente no es /bin/sh
. Tambien comoanotado por peterph), ese shell, dado que se ejecuta de forma interactiva, normalmente leerá archivos de configuración como ~/.zshrc
(si el shell es zsh
) donde algunas configuraciones pueden afectar la forma en que se realiza la globalización.
Por ejemplo:
Mi caparazón es zsh
y tengo un setopt dotglob
en mi ~/.zshrc
, entonces:
$ echo *
.a d é f
Sin leer el ~/.zshrc
:
$ zsh -c 'echo *'
d é f
$ LC_ALL=C zsh -c 'echo *'
d f é
Notarás que eso zsh
respeta la configuración regional al ordenar la lista.
$ sh -c 'echo *'
d f é
sh
(que en mi caso es Debian ash
) no respeta la configuración regional y ordena como si estuviera en la configuración regional C.
Si desea perl
interpretar system()
la línea de comando con un shell en particular, puede escribirlo:
system("zsh", "-c", "cmd");
Cuando se pasa más de un argumento, perl
nunca system()
llama implícitamente a un shell, por lo que arriba, bifurca un proceso en el que se ejecuta /bin/zsh
como ["zsh", "-c", "cmd"]
argumentos.