이전의 조언 $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 (
sh
Solaris와 같은 일부 상용 Unices의 POSIX로 발견 된 경우 포함)을 포함한 일부 쉘은 여전히 그렇게합니다 ( 분할bash
시도도 함) 그 않는 한 리디렉션이 실패 분할이 글 로빙 + 정확히 하나 개의 단어에 결과를 그것에서 리디렉션의 목표를 인용하는 것이 좋습니다 이유입니다,) 당신이로 변환 할 경우에 스크립트 위치를 시스템에 언젠가 스크립트 또는 실행 입니다 해당 지점에서 호환되지 않거나 대화식 쉘에서 제공 될 수 있습니다 .sh
bash
sh
-
산술 표현식 내부. 실제로 변수를 산술 표현식으로 구문 분석하려면 따옴표를 생략해야합니다.
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)}"
명령 출력에서 행 배열을 가져 오는 데 사용 합니다.