다음은 echo $var
방금 할당 된 값과 다른 값을 표시 할 수 있는 일련의 사례 입니다. 이는 할당 된 값이 “큰 따옴표”, “작은 따옴표”또는 따옴표없는 여부에 관계없이 발생합니다.
셸에서 내 변수를 올바르게 설정하려면 어떻게해야합니까?
별표
예상 출력은 /* Foobar is free software */
이지만 대신 파일 이름 목록이 표시됩니다.
$ var="/* Foobar is free software */"
$ echo $var
/bin /boot /dev /etc /home /initrd.img /lib /lib64 /media /mnt /opt /proc ...
대괄호
예상 값은 [a-z]
이지만 때로는 대신 단일 문자가 표시됩니다!
$ var=[a-z]
$ echo $var
c
줄 바꿈 (줄 바꿈)
예상 값은 별도의 줄 목록이지만 대신 모든 값이 한 줄에 있습니다!
$ cat file
foo
bar
baz
$ var=$(cat file)
$ echo $var
foo bar baz
여러 공간
신중하게 정렬 된 표 머리글을 예상했지만 대신 여러 공백이 사라지거나 하나로 축소됩니다!
$ var=" title | count"
$ echo $var
title | count
탭
두 개의 탭으로 구분 된 값을 예상했지만 대신 두 개의 공백으로 구분 된 값을 얻습니다!
$ var=$'key\tvalue'
$ echo $var
key value
답변
위의 모든 경우에서 변수가 올바르게 설정되었지만 올바르게 읽히지 않았습니다! 올바른 방법은 다음을 참조 할 때 큰 따옴표 를 사용하는 것입니다 .
echo "$var"
이것은 주어진 모든 예에서 예상 값을 제공합니다. 항상 변수 참조를 인용하십시오!
왜?
따옴표 가없는 변수는 다음과 같습니다.
-
값이 공백에서 여러 단어로 분할 되는 필드 분할을 수행 합니다 (기본값).
전에:
/* Foobar is free software */
후 :
/*
,Foobar
,is
,free
,software
,*/
-
이러한 각 단어는 패턴이 일치하는 파일로 확장되는 경로 이름 확장 을 거치게됩니다 .
전에:
/*
후 :
/bin
,/boot
,/dev
,/etc
,/home
, … -
마지막으로, 모든 인수는 그들을 기록하는, 에코에 전달되는 하나의 공백으로 구분 주고,
/bin /boot /dev /etc /home Foobar is free software Desktop/ Downloads/
변수의 값 대신.
변수를 인용 하면 다음과 같습니다.
- 그 가치로 대체하십시오.
- 2 단계는 없습니다.
그렇기 때문에 특별히 단어 분할 및 경로 이름 확장이 필요하지 않는 한 항상 모든 변수 참조를 인용 해야합니다 . shellcheck 와 같은 도구 가 도움이 될 수 있으며 위의 모든 경우에 따옴표 누락에 대해 경고합니다.
답변
왜 이런 일이 발생하는지 알고 싶을 수 있습니다. 다른 사람의 훌륭한 설명 과 함께 셸 스크립트가 공백이나 기타 특수 문자로 인해 질식하는 이유에 대한 참조를 찾으십시오 . 작성한 질 에 유닉스 및 리눅스 :
왜 글을 써야
"$foo"
합니까? 따옴표 없이는 어떻게 되나요?
$foo
“변수의 값을 취한다”는 의미가 아닙니다foo
. 이것은 훨씬 더 복잡한 것을 의미합니다.
- 먼저 변수의 값을 취하십시오.
- 필드 분할 : 해당 값을 공백으로 구분 된 필드 목록으로 처리하고 결과 목록을 작성합니다. 변수가 포함되어 있으면, 예를 들면,
foo * bar
이 단계의 결과는 3 요소 목록foo
,*
,bar
.- 파일 이름 생성 : 각 필드를 glob, 즉 와일드 카드 패턴으로 취급하고이 패턴과 일치하는 파일 이름 목록으로 대체합니다. 패턴이 어떤 파일과도 일치하지 않으면 수정되지 않은 상태로 유지됩니다. 이 예에서는
foo
현재 디렉토리의 파일 목록, 마지막으로
bar
. 현재 디렉토리가 비어있는 경우, 결과는foo
,*
,
bar
.결과는 문자열 목록입니다. 쉘 구문에는 목록 컨텍스트와 문자열 컨텍스트의 두 가지 컨텍스트가 있습니다. 필드 분할 및 파일 이름 생성은 목록 컨텍스트에서만 발생하지만 대부분의 경우입니다. 큰 따옴표는 문자열 컨텍스트를 구분합니다. 큰 따옴표로 묶인 전체 문자열은 분할되지 않는 단일 문자열입니다. (예외 :
"$@"
위치 매개 변수 목록으로 확장하는 경우, 예를 들어 위치 매개 변수가 세 개인 경우"$@"
와 동일합니다"$1" "$2" "$3"
. $ *와 $ @의 차이점 은 무엇입니까? 참조 )
$(foo)
또는 로 명령 대체도 마찬가지 입니다. 참고로, 사용하지 마십시오
`foo``foo`
. 인용 규칙은 이상하고 휴대가 불가능하며 모든 최신 쉘은$(foo)
은 직관적 인 인용 규칙을 제외하고는 절대적으로 동등한 을 제공합니다.산술 대체의 출력도 동일한 확장을 거치지 만 확장 할
IFS
수없는 문자 만 포함하므로 일반적으로 문제 가되지 않습니다 ( 숫자 또는를 포함하지
않는다고 가정-
).큰 따옴표는 언제 필요합니까?를 참조하십시오 . 따옴표를 생략 할 수있는 경우에 대한 자세한 내용은
이 모든 rigmarole이 발생하는 것을 의미하지 않는 한, 변수 및 명령 대체 주위에 항상 큰 따옴표를 사용하는 것을 기억하십시오. 주의하세요. 따옴표를 생략하면 오류뿐만 아니라 보안 허점이 발생할 수 있습니다
.
답변
다른 문제뿐만 아니라 인용 실패에 의해 발생 -n
하고 -e
소비 할 수있는 echo
인수로. (전자 만 POSIX 사양에 따라 합법적 echo
이지만 몇 가지 일반적인 구현은 사양을 위반하고 소비 -e
합니다).
이를 방지하려면 세부 사항이 중요한 경우 대신 사용 하십시오.printf
echo
그러므로:
$ vars="-e -n -a"
$ echo $vars # breaks because -e and -n can be treated as arguments to echo
-a
$ echo "$vars"
-e -n -a
그러나 다음을 사용할 때 올바른 인용이 항상 당신을 구하는 것은 아닙니다 echo
.
$ vars="-n"
$ echo $vars
$ ## not even an empty line was printed
… 그것은 반면 것이다 당신을 저장합니다 printf
:
$ vars="-n"
$ printf '%s\n' "$vars"
-n
답변
정확한 값을 얻으려면 사용자 큰 따옴표. 이렇게 :
echo "${var}"
그리고 그것은 당신의 가치를 정확하게 읽을 것입니다.
답변
echo $var
출력은 IFS
변수 의 값에 크게 의존 합니다. 기본적으로 공백, 탭 및 개행 문자가 포함됩니다.
[ks@localhost ~]$ echo -n "$IFS" | cat -vte
^I$
즉, 쉘이 필드 분할 (또는 단어 분할)을 수행 할 때 이러한 모든 문자를 단어 구분 기호로 사용합니다. 이것은 큰 따옴표없이 변수를 참조하여 에코 ($var
)하여 예상 출력이 변경 될 .
단어 분할을 방지하는 한 가지 방법 (큰 따옴표 사용 외에)은 IFS
null 로 설정 하는 것입니다. http://pubs.opengroup.org/onlinepubs/009695399/utilities/xcu_chap02.html#tag_02_06_05 참조 :
IFS 값이 null이면 필드 분할이 수행되지 않습니다.
null로 설정하면 빈 값으로 설정됩니다.
IFS=
테스트:
[ks@localhost ~]$ echo -n "$IFS" | cat -vte
^I$
[ks@localhost ~]$ var=$'key\nvalue'
[ks@localhost ~]$ echo $var
key value
[ks@localhost ~]$ IFS=
[ks@localhost ~]$ echo $var
key
value
[ks@localhost ~]$
답변
ks1322 의 답변은 사용하는 동안 문제를 식별하는 데 도움이되었습니다.docker-compose exec
.
-T
플래그 를 생략하고 docker-compose exec
출력을 중단하는 특수 문자를 추가하면 b
대신 다음이 표시 됩니다 1b
.
$ test=$(/usr/local/bin/docker-compose exec db bash -c "echo 1")
$ echo "${test}b"
b
echo "${test}" | cat -vte
1^M$
-T
플래그를 사용하면 docker-compose exec
예상대로 작동합니다.
$ test=$(/usr/local/bin/docker-compose exec -T db bash -c "echo 1")
$ echo "${test}b"
1b
답변
변수를 따옴표로 묶는 것 외에도 tr
공백을 사용 하고 개행 문자로 변환 하여 변수의 출력을 변환 할 수도 있습니다 .
$ echo $var | tr " " "\n"
foo
bar
baz
이것은 조금 더 복잡하지만 배열 변수 사이의 구분 기호로 모든 문자를 대체 할 수 있으므로 출력에 더 많은 다양성을 추가합니다.