Bash 셸에서 $ {var}, "$ var"및 "$ {var}"의 차이점은 무엇입니까?


133

제목의 말씀 : 그것은의 변수 캡슐화을 의미 하는가 무엇을 {}, ""또는 "{}? "를 나는 이것에 대해 온라인 어떤 설명을 찾을 수 없어 - 나는 상징을 사용하는 것을 제외하고는, 그들에게 참조 할 수되지 않은 아무것도 생산하지 않습니다.

예를 들면 다음과 같습니다.

declare -a groups

groups+=("CN=exampleexample,OU=exampleexample,OU=exampleexample,DC=example,DC=com")
groups+=("CN=example example,OU=example example,OU=example example,DC=example,DC=com")

이:

for group in "${groups[@]}"; do
    echo $group
done

이것과는 많이 다르다는 것을 증명합니다 :

for group in $groups; do
    echo $group
done

이:

for group in ${groups}; do
    echo $group
done

첫 번째 것만으로 원하는 것을 달성합니다. 배열의 각 요소를 반복합니다. 나는의 차이점에 정말 명확하지 않다 $groups, "$groups", ${groups}"${groups}". 누구나 설명 할 수 있다면 고맙겠습니다.

추가 질문으로-이 캡슐화를 참조하는 허용되는 방법을 아는 사람이 있습니까?


답변:


228

괄호 ( $var${var})

대부분의 경우 $var${var}동일합니다 :

var=foo
echo $var
# foo
echo ${var}
# foo

중괄호는 표현식의 모호성을 해결하는 데만 필요합니다.

var=foo
echo $varbar
# Prints nothing because there is no variable 'varbar'
echo ${var}bar
# foobar

따옴표 ( $var"$var""${var}")

변수 주위에 큰 따옴표를 추가하면 공백이 포함되어 있어도 쉘에 단일 단어로 취급하도록 지시합니다.

var="foo bar"
for i in "$var"; do # Expands to 'for i in "foo bar"; do...'
    echo $i         #   so only runs the loop once
done
# foo bar

이 동작을 다음과 대조하십시오.

var="foo bar"
for i in $var; do # Expands to 'for i in foo bar; do...'
    echo $i       #   so runs the loop twice, once for each argument
done
# foo
# bar

와 마찬가지로 $var${var}, 중괄호은 예를 들어, 동음이 필요하다 :

var="foo bar"
for i in "$varbar"; do # Expands to 'for i in ""; do...' since there is no
    echo $i            #   variable named 'varbar', so loop runs once and
done                   #   prints nothing (actually "")

var="foo bar"
for i in "${var}bar"; do # Expands to 'for i in "foo barbar"; do...'
    echo $i              #   so runs the loop once
done
# foo barbar

참고 "${var}bar"두 번째 예에서는 상기도 기록 할 수 "${var}"bar있으며,이 경우에 당신은 즉, 더 이상 괄호가 필요하지 않습니다 "$var"bar. 그러나 문자열에 따옴표가 많으면 이러한 대체 양식을 읽기가 어려워 유지 관리가 어려울 수 있습니다. 이 페이지 는 Bash 인용에 대한 좋은 소개를 제공합니다.

배열 ( $var$var[@]vs. ${var[@]})

이제 배열을 위해. bash 매뉴얼 에 따르면 :

첨자가없는 배열 변수를 참조하는 것은 첨자가 0 인 배열을 참조하는 것과 같습니다.

다시 말해,로 색인을 제공하지 않으면 []배열의 첫 번째 요소를 얻게됩니다.

foo=(a b c)
echo $foo
# a

정확히 같은

foo=(a b c)
echo ${foo}
# a

배열의 모든 요소를 ​​가져 오려면 @인덱스 로 사용해야 합니다 (예 :) ${foo[@]}. 괄호는 배열이 없으면 셸이 $foo부분을 ​​먼저 확장 하여 배열의 첫 번째 요소와 리터럴을 제공하므로 배열에 필요합니다 [@].

foo=(a b c)
echo ${foo[@]}
# a b c
echo $foo[@]
# a[@]

이 페이지 는 Bash의 배열에 대한 좋은 소개입니다.

재 방문한 따옴표 ( ${foo[@]}vs. "${foo[@]}")

당신은 이것에 대해 묻지 않았지만 알기에 좋은 미묘한 차이입니다. 배열의 요소에 공백이 포함될 수있는 경우 각 요소가 별도의 "단어"로 처리되도록 큰 따옴표를 사용해야합니다.

foo=("the first" "the second")
for i in "${foo[@]}"; do # Expands to 'for i in "the first" "the second"; do...'
    echo $i              #   so the loop runs twice
done
# the first
# the second

이것을 큰 따옴표없이 동작과 대조하십시오 :

foo=("the first" "the second")
for i in ${foo[@]}; do # Expands to 'for i in the first the second; do...'
    echo $i            #   so the loop runs four times!
done
# the
# first
# the
# second

3
${var:?}변수가 설정되지 않았거나 설정되지 않은 경우 오류가 발생하는 다른 경우가 있습니다 . REF : github.com/koalaman/shellcheck/wiki/SC2154
남 응 우옌

4
당신이 다른 형태에 대해 이야기하려면 @NamNguyen 매개 변수 확장 :보다 적어도 다스가 ${parameter:-word}, ${parameter:=word}, ${parameter#word}, ${parameter/pattern/string}, 등. 나는 이것 들이이 답변의 범위를 벗어난 것이라고 생각합니다.
ThisSuitIsBlackNot

실제로 큰 따옴표에 대한 논의는 불완전합니다. 추가 stackoverflow.com/questions/10067266/…
tripleee

11

TL; DR

제공하는 모든 예제는 Bash Shell Expansions의 변형입니다 . 확장은 특정 순서로 발생하며 일부는 특정 사용 사례가 있습니다.

토큰 구분 기호로 중괄호

${var}구문은 모호한 토큰을 구분하는 데 주로 사용됩니다. 예를 들어 다음을 고려하십시오.

$ var1=foo; var2=bar; var12=12
$ echo $var12
12
$ echo ${var1}2
foo2

어레이 확장 중괄호

괄호는 배열 의 요소에 액세스하고 다른 특수 확장에 필요 합니다. 예를 들면 다음과 같습니다.

$ foo=(1 2 3)

# Returns first element only.
$ echo $foo
1

# Returns all array elements.
$ echo ${foo[*]}
1 2 3

# Returns number of elements in array.
$ echo ${#foo[*]}
3

토큰 화

나머지 질문의 대부분은 인용 및 쉘이 입력을 토큰 화하는 방법과 관련이 있습니다. 다음 예제에서 쉘이 단어 분리 를 수행하는 방법의 차이점을 고려하십시오 .

$ var1=foo; var2=bar; count_params () { echo $#; }

# Variables are interpolated into a single string.
$ count_params "$var1 $var2"
1

# Each variable is quoted separately, created two arguments.
$ count_params "$var1" "$var2"
2

@기호는 다르게 인용과 상호 작용한다 *. 구체적으로 특별히:

  1. $@ "[e] xp로 시작하고 위치 매개 변수는 1부터 시작합니다. 큰 따옴표 내에서 확장이 발생하면 각 매개 변수는 별도의 단어로 확장됩니다."
  2. 배열에서, "[i] f 단어는 큰 따옴표로 ${name[*]}묶어 각 배열 구성원의 값을 IFS 변수의 첫 문자로 분리하여 단일 단어로 ${name[@]}확장하고 이름의 각 요소를 별도의 단어로 확장합니다."

다음과 같이 실제로 작동하는 것을 볼 수 있습니다.

$ count_params () { echo $#; }
$ set -- foo bar baz 

$ count_params "$@"
3

$ count_params "$*"
1

변수가 공백이나 특수 문자가있는 값을 참조하여 쉘이 의도 한 방식으로 단어를 분리하지 못하게 할 때 인용 확장을 사용하는 것이 중요합니다. Bash에서 인용이 작동하는 방법에 대한 자세한 내용은 인용 을 참조하십시오 .


7

배열과 간단한 변수를 구별해야합니다. 예제에서는 배열을 사용하고 있습니다.

일반 변수의 경우 :

  • $var${var}정확히 동일합니다.
  • "$var""${var}"정확히 동일합니다.

그러나 두 경우 모두 100 % 동일하지는 않습니다. 아래 출력을 고려하십시오.

$ var="  abc  def  "
$ printf "X%sX\n" $var
XabcX
XdefX
$ printf "X%sX\n" "${var}"
X  abc  def  X
$

변수 주위에 큰 따옴표가 없으면 내부 간격이 없어지고 확장은 printf명령 에 대한 두 개의 인수로 처리됩니다 . 변수 주위에 큰 따옴표를 사용하면 내부 간격이 유지되고 확장은 printf명령 에 대한 하나의 인수로 처리됩니다 .

배열을 사용하면 규칙이 비슷하고 다릅니다.

  • 경우 groups참조하는 배열이다 $groups또는 ${groups}참조 동등하다 ${groups[0]}어레이의 영차 소자.
  • 참조 "${groups[@]}"는 참조 와 유사합니다 "$@". 배열의 개별 요소에 간격을 유지하고 배열의 요소 당 하나의 값으로 값 목록을 반환합니다.
  • ${groups[@]}큰 따옴표가없는 참조 는 간격을 유지하지 않으며 일부 요소에 공백이 있으면 배열에있는 요소보다 많은 값을 도입 할 수 있습니다.

예를 들면 다음과 같습니다.

$ groups=("abc def" "  pqr  xyz  ")
$ printf "X%sX\n" ${groups[@]}
XabcX
XdefX
XpqrX
XxyzX
$ printf "X%sX\n" "${groups[@]}"
Xabc defX
X  pqr  xyz  X
$ printf "X%sX\n" $groups
XabcX
XdefX
$ printf "X%sX\n" "$groups"
Xabc defX
$

*대신에 사용하면 @미묘하게 다른 결과가 나타납니다.

스크립트 에서 인수를 반복하는 방법을bash 참조하십시오 .


3

아래의 첫 번째 단락의 두 번째 문장 매개 변수 확장 에는 man bash말한다

확장 될 매개 변수 이름 또는 기호는 중괄호로 묶을 수 있으며, 선택 사항이지만 변수가 이름 바로 뒤에 오는 문자에서 확장되도록 변수를 보호하는 역할을합니다.

이름은 단순히 중괄호 이며 주요 목적은 이름의 시작과 끝을 명확히하는 것입니다.

foo='bar'
echo "$foobar"
# nothing
echo "${foo}bar"
barbar

더 자세히 읽으면,

매개 변수가 두 자리 이상의 위치 매개 변수 인 경우 중괄호가 필요합니다…

테스트하자 :

$ set -- {0..100}
$ echo $22
12
$ echo ${22}
20

허. 산뜻한. 나는 이것을 작성하기 전에 솔직히 몰랐다 (이전에 위치 매개 변수가 9 개 이상 없었습니다.)

물론 다음과 같은 강력한 매개 변수 확장 기능을 수행하려면 중괄호가 필요합니다.

${parameter:-word}
${parameter:=word}
${parameter:?word}
 [read the section for more]

뿐만 아니라 배열 확장.


3

위에서 다루지 않은 관련 사례. 빈 변수를 인용하면의 내용이 바뀌는 것 같습니다 test -n. 이것은에 대한 info텍스트 로 구체적으로 coreutils설명되어 있지만 실제로 설명되어 있지는 않습니다.

16.3.4 String tests
-------------------

These options test string characteristics.  You may need to quote
STRING arguments for the shell.  For example:

     test -n "$V"

  The quotes here prevent the wrong arguments from being passed to
`test' if `$V' is empty or contains special characters.

자세한 설명을 듣고 싶습니다. 내 시험이를 확인하고, 지금 피하기 위해, 모든 문자열 테스트를 위해 내 변수를 인용하고 있습니다 -z-n같은 결과를 반환합니다.

$ unset a
$ if [ -z $a ]; then echo unset; else echo set; fi
unset
$ if [ -n $a ]; then echo set; else echo unset; fi    
set                                                   # highly unexpected!

$ unset a
$ if [ -z "$a" ]; then echo unset; else echo set; fi
unset
$ if [ -n "$a" ]; then echo set; else echo unset; fi
unset                                                 # much better

2

글쎄, 변수 캡슐화는 다음과 같은 작업을하는 데 도움이된다는 것을 알고 있습니다.

${groups%example}

값을 반환하기 전에 변수로 무언가를하고 싶은 구문.

코드가 보이면 모든 마법이

${groups[@]}

마법은 거기에 쓸 수 없기 때문에 거기에 있습니다. $groups[@]

{}특수 문자 []및 을 사용하려고하므로 변수를 안에 넣습니다 @. : 당신의 이름 또는 당신의 변수를 호출 할 수 없습니다 @또는 something[]이 다른 운영 및 이름에 예약 된 문자 때문이다.


이것은 큰 따옴표의 중요한 의미를 지적하지 못하며 큰 따옴표가없는 코드는 기본적으로 어떻게 손상되는지 나타냅니다.
tripleee December
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.