printf는 한 줄만 인쇄합니다.

printf는 한 줄만 인쇄합니다.

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의 영향을 받지 않고 줄 바꿈이 유지되며 참조되므로 올바르게 해석되고 인쇄됩니다.foobar

다음 질문은 printf싫어요 입니다 echo. 제공한 내용을 인쇄할 뿐만 아니라 형식 문자열도 필요합니다. 예를 들어 다음과 같이 printf "color:%s" "green"인쇄됩니다 .color:green%sgreen

또한 주어진 형식 문자열에 맞지 않는 모든 입력을 무시합니다. 따라서 를 실행하면 printf foo bar형식 문자열과 형식 지정에 사용되는 변수 printf로 처리됩니다 . no 또는 동등한 항목을 대체할 수 있으므로 무시 되고 별도로 인쇄됩니다.foobar%sbarbarfoo

$ 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:

    1. 따옴표나 형식 지정자가 없으면 첫 번째 단어만 인쇄됩니다.

    2. %따옴표가 있고 형식 지정자가 없으면 확장에 형식 지정자가 있는 모든 항목을 고려하여 차단할 수 있습니다.

    3. 따옴표가 없고 형식 지정자가 있으면 토큰화 및 경로 이름 확장의 영향을 받게 되므로 모든 값이 IFS출력에서 ​​공백이 되므로 예상치 못한 결과가 발생합니다.

    4. 따옴표와 형식 지정자를 사용하면 원하는 결과를 얻을 수 있습니다. 즉, 확장 시 단어 분리 및 경로 이름 확장이 수행되지 않습니다.

  • echo:

    1. 따옴표가 없으면 변수 확장이 토큰화 및 경로 이름 확장의 영향을 받게 되므로 원하는 출력을 얻을 수 없습니다.

    2. 변수 확장을 사용하면 quote토큰화 및 경로 이름 확장의 영향을 받지 않으므로 원하는 결과를 얻을 수 있습니다.

관련 정보