다음과 같은 와일드카드와 함께 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
Perl의 기능은 일반적으로 프로세스를 분기하고 하위 프로세스에서 인수로 system("cmd")
시스템의 쉘(일반적으로 )을 실행하여 해당 쉘 명령줄을 구문 분석하고 실행합니다 ./bin/sh
["sh", "-c", "cmd"]
sh
최적화로서 공백과 탭 이외의 쉘 메타 문자(예: 인용 문자 또는 글로빙 문자 또는 ...와 같은 것)가 포함되지 않은 경우 쉘 호출 없이도 수행될 수 있지만 여기에는 쉘 메타가 있습니다 cmd
. -문자가 있기 때문에 .;
&&
*
따라서 이는 ls -U -1 dir/*
시스템의 쉘에 의해 해석됩니다.
dir/*
에 전달된 일치하는 파일 목록을 확장하는 것은 셸이므로 ls
수행 방법은 셸에 따라 다릅니다.
터미널에서는 일반적으로 로그인 셸을 실행하지만 일반적으로 /bin/sh
. 또한 (피터프가 언급한), 해당 셸은 대화형으로 실행되므로 일반적으로 일부 설정이 글로빙 수행 방법에 영향을 미칠 수 있는 구성 파일을 읽습니다 ~/.zshrc
(셸이 ).zsh
예를 들어:
내 쉘은 이고 , 내 에는 zsh
a가 있으므로 다음과 같습니다.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");
하나 이상의 인수가 전달되면 perl
'은 (는 system()
) 암시적으로 쉘을 호출하지 않으므로 위에서는 인수 /bin/zsh
로 실행되는 프로세스를 분기합니다.["zsh", "-c", "cmd"]