여러 개의 파일과 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
.Peterv가 지적했습니다.), 셸은 대화형으로 실행되기 때문에 일반적으로 구성 파일을 읽습니다. 예를 들어 ~/.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
(내 경우 데비안 ash
)은 로케일을 존중하지 않으며 C 로케일처럼 정렬됩니다.
perl
특정 쉘을 사용하여 system()
명령줄을 해석하려면 다음과 같이 작성할 수 있습니다 .
system("zsh", "-c", "cmd");
perl
s는 여러 인수를 전달할 때 system()
암시적으로 쉘을 호출하지 않으므로 위의 프로세스는 프로세스를 분기하고 해당 프로세스에서 인수 /bin/zsh
로 ["zsh", "-c", "cmd"]
실행합니다 .