이전의 조언 $VARIABLE은 적어도 하나의 쉘이 하나의 단일 항목으로 해석되기를 원한다면을 포함하는 표현을 이중 인용하는 것이 었습니다. 그렇지 않으면 내용의 모든 공백 $VARIABLE이 쉘을 버릴 것입니다.
그러나 최신 버전의 셸에서는 더 이상 큰 따옴표가 더 이상 필요하지 않습니다 (적어도 위에서 설명한 목적으로). 예를 들어,에 bash:
% FOO='bar baz'
% [ $FOO = 'bar baz' ] && echo OK
bash: [: too many arguments
% [[ $FOO = 'bar baz' ]] && echo OK
OK
% touch 'bar baz'
% ls $FOO
ls: cannot access bar: No such file or directory
ls: cannot access baz: No such file or directory
에서 zsh, 다른 한편으로는, 같은 세 가지 명령은 성공. 따라서이 실험에 따르면 in bash에서 큰 따옴표를 생략 할 수 [[ ... ]]있지만 내부 [ ... ]또는 명령 줄 인수에서는 생략 할 수 없지만 ,에서 zsh따옴표는 생략 할 수 있습니다.
그러나 위와 같은 일화적인 예에서 일반적인 규칙을 추론하는 것은 찬성입니다. 큰 따옴표가 필요한 경우에 대한 요약을 보는 것이 좋습니다. 나는에 주로 관심이 있어요 zsh, bash하고 /bin/sh.
답변
먼저 zsh를 나머지와 분리하십시오. 오래된 쉘과 현대 쉘의 문제는 아닙니다. zsh는 다르게 동작합니다. zsh 디자이너는 기존 쉘 (Bourne, ksh, bash)과 호환되지 않지만 사용하기 쉽게하기로 결정했습니다.
둘째, 큰 따옴표를 필요할 때 기억하는 것보다 항상 사용하는 것이 훨씬 쉽습니다. 대부분의 시간이 필요하므로 필요할 때가 아니라 필요하지 않은시기를 배워야합니다.
간단히 말해서 단어 목록이나 패턴이 예상되는 곳에는 큰 따옴표가 필요 합니다. 파서가 원시 문자열을 예상하는 상황에서는 선택 사항입니다.
따옴표없이 일어나는 일
큰 따옴표가 없으면 두 가지 일이 발생합니다.
- 먼저, 확장 결과 (와 같은 매개 변수 대체에 대한 변수 값
${foo}또는 같은 명령 대체에 대한 명령의 출력$(foo))는 공백이 포함 된 곳마다 단어로 분할됩니다.
보다 정확하게는 확장 결과는IFS변수 값 (분리 문자)에 나타나는 각 문자로 분할됩니다 . 일련의 구분 문자에 공백 (공백, 탭 또는 줄 바꿈)이 포함 된 경우 공백은 단일 문자로 계산됩니다. 공백이 아닌 구분 기호를 선행, 후행 또는 반복하면 빈 필드가 생깁니다. 예를 들어,와IFS=" :",:one::two : three: :four이전에 빈 필드를 생산one사이one와two사이에, 그리고 (하나 하나)three와four. - 분할 결과로 생성 된 각 필드는 문자 중 하나가 포함 된 경우 글로브 (와일드 카드 패턴)로 해석됩니다
\[*?. 해당 패턴이 하나 이상의 파일 이름과 일치하면 패턴이 일치하는 파일 이름 목록으로 바뀝니다.
인용 부호가없는 변수 확장 $foo은 구어체 적으로 “split + glob operator”로 알려져 있지만 "$foo", 변수의 값만 취합니다 foo. 명령 대체도 마찬가지 "$(foo)"입니다. 명령 대체 $(foo)입니다. 명령 대체는 split + glob입니다.
큰 따옴표를 생략 할 수있는 곳
Bourne 스타일 쉘에서 생각할 수있는 모든 경우는 큰 따옴표없이 변수 또는 명령 대체를 쓸 수 있으며 값은 문자 그대로 해석됩니다.
-
과제의 오른쪽에.
var=$stuff a_single_star=*뒤에 큰 따옴표가 필요합니다
export. 키워드가 아닌 일반적인 내장 기능이기 때문입니다. 이것은 대시, zsh (sh 에뮬레이션에서), yash 또는 posh와 같은 일부 쉘에서만 적용됩니다. bash와 ksh는 모두export특별하게 취급 합니다.export VAR="$stuff" -
A의
case문.case $var in …대소 문자 패턴에는 큰 따옴표가 필요합니다. 대소 문자 패턴에서는 단어 분리가 발생하지 않지만 인용되지 않은 변수는 패턴으로 해석되고 인용 된 변수는 리터럴 문자열로 해석됩니다.
a_star='a*' case $var in "$a_star") echo "'$var' is the two characters a, *";; $a_star) echo "'$var' begins with a";; esac -
이중 괄호 안에 이중 괄호는 쉘 특수 구문입니다.
[[ -e $filename ]]패턴 또는 정규식이 예상되는 경우에는 큰 따옴표가 필요하다는 점을 제외하고 :
=또는==or!=또는 오른쪽에=~.a_star='a*' if [[ $var == "$a_star" ]]; then echo "'$var' is the two characters a, *" elif [[ $var == $a_star ]]; then echo "'$var' begins with a" fi작은 괄호 안에는 큰 따옴표가 필요합니다. 대괄호
[ … ]는 일반적인 셸 구문이기 때문입니다 (라고하는 명령입니다[). 단일 또는 이중 괄호 참조 -
비 대화식 POSIX 셸에서 리디렉션 (not
bash및 norksh88)echo "hello world" >$filename일부 쉘은 대화식 일 때 변수 값을 와일드 카드 패턴으로 처리합니다. POSIX는 비 대화식 쉘에서의 동작을 금지하지만 bash (POSIX 모드 제외) 및 ksh88 (
shSolaris와 같은 일부 상용 Unices의 POSIX로 발견 된 경우 포함)을 포함한 일부 쉘은 여전히 그렇게합니다 ( 분할bash시도도 함) 그 않는 한 리디렉션이 실패 분할이 글 로빙 + 정확히 하나 개의 단어에 결과를 그것에서 리디렉션의 목표를 인용하는 것이 좋습니다 이유입니다,) 당신이로 변환 할 경우에 스크립트 위치를 시스템에 언젠가 스크립트 또는 실행 입니다 해당 지점에서 호환되지 않거나 대화식 쉘에서 제공 될 수 있습니다 .shbashsh -
산술 표현식 내부. 실제로 변수를 산술 표현식으로 구문 분석하려면 따옴표를 생략해야합니다.
expr=2*2 echo "$(($expr))"그러나 POSIX에서 요구하는대로 대부분의 쉘에서 단어 분할이 적용되므로 산술 확장에 따옴표가 필요합니다 (!?).
-
연관 배열 아래 첨자.
typeset -A a i='foo bar*qux' a[foo\ bar\*qux]=hello echo "${a[$i]}"
인용되지 않은 변수 및 명령 대체는 드문 경우에 유용 할 수 있습니다.
- 변수 값 또는 명령 출력이 glob 패턴 목록으로 구성되고 이러한 패턴을 일치하는 파일 목록으로 확장하려는 경우.
- 값에 와일드 카드 문자가 포함되어 있지 않다는 것을 알면
$IFS수정되지 않았으며 공백 문자로 분할하려고합니다. - 특정 문자에서 값을 분할하려면을 사용하여 globbing을 비활성화 하고 구분 문자로
set -f설정IFS하거나 공백으로 분리하려면 그대로 두십시오.
Zsh
zsh에서는 몇 가지 예외를 제외하고 대부분 큰 따옴표를 생략 할 수 있습니다.
-
$var여러 단어로 확장되지는 않지만 값이var빈 문자열 인 경우 빈 목록 (한 개의 빈 단어가 포함 된 목록과 반대)으로 확장됩니다 . 대조:var= print -l $var foo # prints just foo print -l "$var" foo # prints an empty line, then foo마찬가지로,
"${array[@]}"배열의 모든 요소로$array확장되고 비어 있지 않은 요소로만 확장됩니다. -
@매개 변수 확장 플래그 때로는 전체 대체 주위에 따옴표가 필요합니다"${(@)foo}". -
: 명령 치환은 필드 분할 인용 부호로 둘러싸이지 않은 경우에 거쳐
echo $(echo 'a'; echo '*')인쇄a *반면 (하나의 공간)echo "$(echo 'a'; echo '*')"수정되지 않은 두 줄의 문자열을 인쇄합니다. 한"$(somecommand)"줄로 명령의 출력을 얻기 위해 사용하십시오 ."${$(somecommand; echo _)%?}"최종 개행을 포함하여 명령의 정확한 출력을 얻는 데 사용하십시오 ."${(@f)$(somecommand)}"명령 출력에서 행 배열을 가져 오는 데 사용 합니다.