간결한 버전:
내 Mac의 bash 블록 내에서 확장된 glob을 열 때 if
전체 블록이 활성화된 후에도 블록 내에 포함된 확장된 glob 패턴에서 구문 오류로 인해 실패합니다. 다른 컴퓨터에서는 문제가 없습니다. 왜?
긴 버전:
if
파일 전체에 다음과 같은 조건을 설정했습니다 .bashrc
. 쉘 초기화 중에 실행되는 if
다른 파일에도 유사한 명령문이 있습니다 . .*
나중에 문제가 발생할 경우 파일이 재귀적으로 실행되는 것을 방지하기 위해 이렇게 합니다.
if [ -n "${_BASHRC_INIT}" ] ; then
export _BASHRC_INIT="True"
...
...
...
unset _BASHRC_INIT
fi
laa
.bashrc
확장된 glob에 의존하는 이 함수가 my에 정의되어 있습니다 . 함수를 정의하기 직전에 활성화합니다. 이 기능은 .*
제외 및 일치하는 디렉토리의 .
모든 파일을 표시합니다 ..
. ls
별칭을 지정 했기 때문에 ls --color=auto
파일 형식 색상도 표시되는데, grep
. if
블록 내부가 아닐 때 작동합니다 .
shopt -s extglob
laa() {
if [[ $# -eq 1 ]]; then
exec 3>&1 # Another file descriptor for this STDOUT
_items=$(cd "${1}"; ls -d .!(|.)?* 1>&3) # This requires extended glob
# `shopt -s extglob` to enable
exec 3>&- # Close file descriptor
elif [ $# -gt 1 ]; then
exec 3>&1
for i in $@; do
_items=$(cd $i; echo "$i:" 1>&3; ls -d .!(|.)* 1>&3)
done
exec 3>&-
else
ls -d .!(|.)*
fi
}
블록에 이 발췌문도 포함되어 있으면 블록에 포함된 명령 중 어떤 것도 if
내 M1 Mac에서 실행될 수 없습니다 . 내 Windows PC의 WSL2(Debian)에서는 이 문제가 발생하지 않습니다. Mac은 bash 5.2.15
Homebrew 및 WSL 실행이 설치된 상태로 실행됩니다 bash 5.1.4
.
ls
특히 다음 오류로 인해 명령이 실패합니다 .
bash: syntax error near unexpected token `('
bash: ` _items=$( cd "${1}"; ls -d .!(|.)?* 1>&3 ) # This requires extended glob'
입력 전에 실행하면 전체 if
블록이 예상대로 실행됩니다. shopt -t extglob
이것이 나의 현재 솔루션입니다. 그러나 이는 내 환경에서 설정하려는 규칙을 깨뜨립니다. 나는 .*
내 컴퓨터에서 동일한 파일을 사용하려고 노력하는데, 이는 새 컴퓨터에서 일관된 환경을 빠르게 만드는 데도 도움이 됩니다.
블록 내용에 대한 추가 구문 검사의 원인은 무엇입니까 if
?
답변1
여기에서는 KSH 스타일 확장 글로브를 완전히 피할 수 있습니다.- 예를 참조하세요.현재 디렉터리와 상위 디렉터리를 제외한 모든 숨겨진 파일을 전역적으로 표시하는 방법.
compat51
아래6.12 셸 호환 모드
명령 대체 구문 분석은 확장 glob이 활성화된 것처럼 작동하므로(Shopt 내장 참조) extglob 패턴(예: 쉘 함수의 일부)이 포함된 명령 대체 구문 분석은 실패하지 않습니다. 이는 명령을 실행하고 단어 확장을 수행하기 전에 extglob을 활성화하려는 의도가 있다고 가정합니다. 명령이 실행될 때 extglob이 활성화되지 않으면 단어 확장 시 실패합니다.
예를 들어 고려하십시오.
#!/bin/bash
echo "$BASH_VERSION"
laa() {
if [[ $# -eq 1 ]]; then
exec 3>&1 # Another file descriptor for this STDOUT
_items=$(cd "${1}"; ls -d .!(|.)?* 1>&3) # This requires extended glob
# `shopt -s extglob` to enable
exec 3>&- # Close file descriptor
elif [ $# -gt 1 ]; then
exec 3>&1
for i in $@; do
_items=$(cd $i; echo "$i:" 1>&3; ls -d .!(|.)* 1>&3)
done
exec 3>&-
fi
}
shopt -s extglob
laa .
여기서는 extglob
함수 정의 후 실행 전에 설정됩니다(함수가 .bashrc 파일에서 시작된 경우). bash 5.1에서는 작동합니다.
$ /bin/bash ./myscript
5.1.16(1)-release
.admins .cache .hardinfo .parallel .RData .ssh .vboxclient-display-svga-x11.pid .Xauthority .zcompdump
.bash_history .config .lesshst .password-store .Rhistory .sudo_as_admin_successful .vboxclient-draganddrop.pid .xinitrc .zsh_history
.bash_logout .dialogrc .local .profile .selected_editor .test_dot_folder .vboxclient-seamless.pid .xscreensaver .zshrc
.bashrc .gnupg .mozilla .python_history .spectrum3d .vboxclient-clipboard.pid .wget-hsts .xsession-errors
5.2에서는 다음을 수행하지 않습니다.
$ ./src/bash-5.2.15/bash ./myscript
5.2.15(1)-release
./myscript: line 8: syntax error near unexpected token `('
./myscript: line 8: ` _items=$(cd "${1}"; ls -d .!(|.)?* 1>&3) # This requires extended glob'
하지만, 행동외부명령 대체의 상황은 동일하므로 else
블록을 추가한 후에는 다음과 같습니다.
#!/bin/bash
echo "$BASH_VERSION"
laa() {
if [[ $# -eq 1 ]]; then
exec 3>&1 # Another file descriptor for this STDOUT
_items=$(cd "${1}"; ls -d .!(|.)?* 1>&3) # This requires extended glob
# `shopt -s extglob` to enable
exec 3>&- # Close file descriptor
elif [ $# -gt 1 ]; then
exec 3>&1
for i in $@; do
_items=$(cd $i; echo "$i:" 1>&3; ls -d .!(|.)* 1>&3)
done
exec 3>&-
else
ls -d .!(|.)*
fi
}
shopt -s extglob
laa .
두 경우 모두 코드가 실패합니다. 5.2에서는 더 빠릅니다.
$ ./src/bash-5.2.15/bash ./myscript
5.2.15(1)-release
./myscript: line 8: syntax error near unexpected token `('
./myscript: line 8: ` _items=$(cd "${1}"; ls -d .!(|.)?* 1>&3) # This requires extended glob'
$
$ /bin/bash ./myscript
5.1.16(1)-release
./myscript: line 18: syntax error near unexpected token `('
./myscript: line 18: ` ls -d .!(|.)*'
bash 5.1 동작을 사용해야 하는 경우 BASH_COMPAT=51
.bashrc 파일의 함수 정의 전에 이를 설정할 수 있습니다.