변수를 참조해야 하는데 echo는 참조하지 않는 이유는 무엇입니까?

변수를 참조해야 하는데 echo는 참조하지 않는 이유는 무엇입니까?

변수를 확장하려면 큰따옴표가 필요하다는 것을 읽었습니다.

if [ -n "$test" ]; then echo '$test ok'; else echo '$test null'; fi

예상대로 작동하지만

if [ -n $test ]; then echo '$test ok'; else echo '$test null'; fi

$test oknull 인 경우에도 항상 호출됩니다 $test.

그런데 왜 따옴표가 필요하지 않습니까 echo $test?

답변1

모든 변수에는 항상 따옴표가 필요합니다.목록즉, 변수를 인용되지 않은 상태로 두는 데 따른 3가지 부작용을 실제로 원하지 않는 한 변수는 어디에서나 여러 값으로 확장될 수 있습니다.

목록컨텍스트에는 [또는 echo, for i in <here>배열에 대한 할당과 같은 간단한 명령의 매개 변수가 포함됩니다. 다른 컨텍스트도 있으며 변수도 참조해야 합니다. 타당한 이유가 없는 한 항상 변수를 인용하는 것이 가장 좋습니다.

고려하면따옴표 없음(목록 컨텍스트에서) 다음과 같이분할+전역운영자.

마치 .echo $testecho glob(split("$test"))

puts("foo")대부분의 다른 언어에서는 변수(예: ) 주위가 아닌 고정 문자열 주위에 따옴표를 붙이는 puts(var)반면, 셸에서는 그 반대입니다. 즉, 셸의 모든 것은 모두 문자열입니다. 따라서 모든 것에 따옴표를 붙이는 것은 번거로울 수 있으며, 여러분은 echo test그럴 필요가 없습니다 "echo" "test". 셸에서 따옴표는 다른 목적, 즉 특정 문자의 특별한 의미를 방지하거나 특정 확장자의 동작에 영향을 주기 위해 사용됩니다.

[ -n $test ]or 에서 echo $test쉘은 분할 $test(기본적으로 공백)을 수행한 다음 파일 이름 생성(모든 *'?'... 패턴을 일치하는 파일 목록으로 확장)을 수행한 다음 해당 인수 목록을 [or echo명령에 전달합니다.

다시 한번 생각해 보세요 "[" "-n" glob(split("$test")) "]". 비어 있거나 공백(spc, tab, nl)만 포함하는 경우 $test분할+glob 연산자는 빈 목록을 반환하므로 "-n"이 빈 문자열인지 확인하는 테스트인 가 [ -n $test ]됩니다 . "[" "-n" "]"하지만 $test"*" 또는 "= foo"라면 어떤 일이 일어날지 상상해 보세요...

, 및 (따옴표 없이) 에는 4개의 매개변수 가 전달되는데 [ -n "$test" ], 이는 우리가 원하는 것입니다.["[""-n""""]"

echo전달 여부는 [아무런 차이가 없습니다 echo. 단지 빈 매개변수를 전달하든 매개변수를 전혀 전달하지 않든 동일한 내용이 출력된다는 점만 다를 뿐입니다.

당신은 또한 볼 수 있습니다이 비슷한 질문에 대한 대답[명령 및 구성 에 대한 [[...]]자세한 내용 .

답변2

@h3rrmiller의 답변if따옴표 (또는 오히려 [/ ) 가 필요한 이유를 설명하는 데 도움이 되지만 test실제로는 귀하의 질문이 잘못된 것 같습니다.

다음 명령을 시도해 보면 무슨 뜻인지 알 수 있을 것입니다.

export testvar="123    456"
echo $testvar
echo "$testvar"

따옴표가 없으면 변수 대체로 인해 두 번째 명령이 다음으로 확장됩니다.

echo 123    456

그리고 여러 공간이 하나로 축소됩니다.

echo 123 456

따옴표를 사용하면 공백이 유지됩니다.

이런 일이 일어나는 이유는매개변수를 인용하면( 매개변수가 로 전달되거나 다른 명령으로 전달되는지 여부 echo) test매개변수의 값이 다음과 같이 전달됩니다.하나명령의 값입니다. 인용하지 않으면 쉘은 각 인수가 시작되고 끝나는 위치를 결정하기 위해 공백을 찾는 일반적인 마법을 수행합니다.

이는 다음의 (매우, 매우 간단한) C 프로그램으로도 설명할 수 있습니다. 명령줄에서 다음을 시도해 보십시오(무언가를 덮어쓸 위험이 없도록 빈 디렉토리에서 이 작업을 수행할 수 있습니다).

cat <<EOF >paramtest.c
#include <stdio.h>
int main(int argc, char **argv) {
  int nparams = argc-1; /* because 1 parameter means only the executable's name */
  printf("%d parameters received\n", nparams);
  return nparams;
}
EOF
cc -o paramtest paramtest.c

그런 다음...

./paramtest 123 456
./paramtest "123 456"
./paramtest 123   456
./paramtest "123   456"

paramtest를 실행 한 후 $?전달된 인수의 개수가 저장됩니다(그리고 해당 개수가 인쇄됩니다).

답변3

이것이 쉘이 행의 전체 내용을 해석하는 방법입니다.앞으로프로그램이 실행됩니다.

줄이 로 읽히면 echo I am $USER쉘은 이를 로 확장 echo I am blrfl하고 echo텍스트 소스가 리터럴인지 변수 확장인지 알 수 없습니다. 마찬가지로 줄에 가 포함되어 있으면 echo I am $UNDEFINED쉘은 $UNDEFINED아무 것도 확장되지 않고 echo에 대한 인수는 가 되며 I am그게 끝입니다. echo매개변수 없이 작동하기 때문에 echo $UNDEFINED완전히 유효합니다.

귀하의 질문은 if실제로 문제가 되지 않습니다 if. 왜냐하면 if그 뒤에 오는 모든 프로그램과 인수를 실행하고 then프로그램이 종료될 때 해당 부분을 실행하기 때문입니다 0(또는 else프로그램이 종료되지 않는 경우 해당 부분을 실행하십시오 0).

if /bin/true ; then echo True dat. ; fi
if fgrep -q blrfl /etc/passwd ; then echo Blrfl has an account. ; fi

비교를 수행할 때 if [ ... ]쉘에 내장된 기본 요소를 사용하지 않습니다 . 기본적으로 이라는 프로그램을 실행하도록 쉘에 지시하는 것입니다. [이 프로그램은 해당 프로그램의 아주 작은 상위 집합이며 test(1)마지막 인수는 입니다 ]. 0테스트 조건이 참이거나 1참이 아니면 두 프로그램 모두 종료됩니다.

변수가 정의되지 않았을 때 일부 테스트가 중단되는 이유는 test변수를 사용하고 있다는 것을 알 수 없기 때문입니다. 따라서 [ $UNDEFINED -eq 2 ]쉘이 완료할 때 test표시되는 모든 인수는 -eq 2 ]유효한 테스트가 아니기 때문에 중단됩니다. 정의된 항목(예: [ $DEFINED -ne 0 ])을 사용하여 이 작업을 수행하면 셸이 이를 유효한 테스트(예: )로 확장하므로 작동합니다 0 -ne 0.

사이에는 의미상 차이가 있으며 , 이름에서 알 수 있듯이 두 개의 매개변수( 및 ) foo $UNDEFINED bar로 확장됩니다 . 와 비교하면 다음과 같이 확장됩니다.foobar$UNDEFINEDfoo "$UNDEFINED" bar매개변수( foo, 빈 문자열 및 `bar). 따옴표는 셸이 따옴표 사이에 내용이 있는지 여부에 관계없이 따옴표를 인수로 해석하도록 합니다.

답변4

따옴표가 없으면 빈 매개변수가 제거됩니다.

start cmd:> strace -e trace=execve echo foo $bar baz
execve("/usr/bin/echo", ["echo", "foo", "baz"], [/* 100 vars */]) = 0

start cmd:> strace -e trace=execve echo foo "$bar" baz
execve("/usr/bin/echo", ["echo", "foo", "", "baz"], [/* 100 vars */]) = 0

호출된 명령은 쉘 명령줄에 빈 매개변수를 표시하지 않습니다. [는 -n이 다음 항목 없이 0을 반환하는 것으로 정의된 것 같습니다. 어떤 식으로든.

어떤 경우에는 참조가 에코에 영향을 미칩니다.

var='*'
echo $var
echo "$var"

var="foo        bar"
echo $var
echo "$var"

관련 정보