env
쉘 변수에 출력을 가져와서 인쇄하려고 합니다.
#!/bin/sh
ENV_BEFORE=$(env)
printf $ENV_BEFORE
결과적으로 env
출력의 단일 변수가 인쇄됩니다.
echo
대신 사용하면 printf
줄 바꿈 없이 모든 출력을 인쇄합니다.
내가 여기서 무엇을 놓치고 있는 걸까요?
답변1
문제는 변수에 대한 참조가 없다는 것입니다 $ENV
. 설명된 대로 man bash
:
문자를 큰따옴표로 묶으면 기록 확장이 활성화된 경우 $, `, \ 및 !를 제외한 따옴표 안의 모든 문자의 리터럴 값이 유지됩니다. $ 및 ` 문자는 큰따옴표 안에 특별한 의미를 유지합니다. 백슬래시는 $, `, ", \ 또는 문자 중 하나가 뒤에 오는 경우에만 특별한 의미를 유지합니다..
따라서 시퀀스를 \n
큰따옴표로 묶으면 해당 의미가 유지됩니다. 그렇기 때문에 참조가 없으면 \n
그냥 일반적인 것입니다 n
.
$ printf \n
n$
그리고 인용하면:
$ printf "\n"
$
Bash에서 따옴표가 없는 변수는 Split+glob 연산자를 호출합니다. 이는 변수가 공백(또는 $IFS
특수 변수가 설정된 모든 항목)으로 분할되고 각 결과 단어가 glob(일치하는 파일 이름과 일치하도록 확장됨)으로 사용됨을 의미합니다. 귀하의 문제는 그것의 "분할"부분에 있습니다.
이를 설명하기 위해 더 간단한 여러 줄 변수를 살펴보겠습니다.
$ var=$(printf "foo\nbar\n")
이제 셸의 set -x
디버깅 기능을 사용하여 무슨 일이 일어나고 있는지 정확히 확인할 수 있습니다.
$ echo $var
+ echo foo bar
foo bar
$ echo "$var"
+ echo 'foo
bar'
foo
bar
위에서 볼 수 있듯이 echo $var
(인용되지 않은)은 분할+glob을 따르 므로 두 개의 별도 문자열 및 를 $var
생성합니다 . 개행 문자는 Split+Glob으로 먹습니다. 변수가 참조되면 분할+glob의 영향을 받지 않고 줄 바꿈이 유지되며 참조되므로 올바르게 해석되고 인쇄됩니다.foo
bar
다음 질문은 printf
싫어요 입니다 echo
. 제공한 내용을 인쇄할 뿐만 아니라 형식 문자열도 필요합니다. 예를 들어 다음과 같이 printf "color:%s" "green"
인쇄됩니다 .color:green
%s
green
또한 주어진 형식 문자열에 맞지 않는 모든 입력을 무시합니다. 따라서 를 실행하면 printf foo bar
형식 문자열과 형식 지정에 사용되는 변수 printf
로 처리됩니다 . no 또는 동등한 항목을 대체할 수 있으므로 무시 되고 별도로 인쇄됩니다.foo
bar
%s
bar
bar
foo
$ printf $var
+ printf foo bar
foo
을 실행하면 이런 일이 발생합니다 printf $ENV_BEFORE
. 변수가 참조되지 않기 때문에 분할 glob은 효과적으로 개행을 공백으로 대체하고 printf
보이는 첫 번째 "단어"만 인쇄합니다.
이를 올바르게 수행하려면 형식 문자열을 사용하고 항상 변수를 인용하십시오.
printf '%s\n' "$ENV_BEFORE"
답변2
printf
(with echo
)는 기본적으로 줄바꿈을 인쇄하지 않으므로 명시적으로 알려주어야 합니다.
printf "${ENV_BEFORE}\n"
또는 더 나은:
printf '%s\n' "$ENV_BEFORE"
뒤쪽에@don_crissti댓글에서 올바르게 지적했듯이 질문을 다시 읽어보니 귀하의 상황이 위와 다르다고 생각합니다.
귀하의 경우 문제는 변수에 대한 참조가 없다는 것입니다 $ENV_BEFORE
.
printf
변수를 인용하지 않으면 합계가 어떻게 작동하는지는 다음과 같습니다 .echo
printf
:따옴표나 형식 지정자가 없으면 첫 번째 단어만 인쇄됩니다.
%
따옴표가 있고 형식 지정자가 없으면 확장에 형식 지정자가 있는 모든 항목을 고려하여 차단할 수 있습니다.따옴표가 없고 형식 지정자가 있으면 토큰화 및 경로 이름 확장의 영향을 받게 되므로 모든 값이
IFS
출력에서 공백이 되므로 예상치 못한 결과가 발생합니다.따옴표와 형식 지정자를 사용하면 원하는 결과를 얻을 수 있습니다. 즉, 확장 시 단어 분리 및 경로 이름 확장이 수행되지 않습니다.
echo
:따옴표가 없으면 변수 확장이 토큰화 및 경로 이름 확장의 영향을 받게 되므로 원하는 출력을 얻을 수 없습니다.
변수 확장을 사용하면
quote
토큰화 및 경로 이름 확장의 영향을 받지 않으므로 원하는 결과를 얻을 수 있습니다.