이 효과를 피하십시오

이 효과를 피하십시오

껍데기구조$(...)후행 개행 문자 제거?

#!/bin/bash

S='a
b
'
printf '%i [%s]\n' "${#S}" "$S"

T=$(printf '%s' "$S")
printf '%i [%s]\n' "${#T}" "$T"

이것을 인쇄하세요:

4 [a
b
]
3 [a
b]

이 변수 S에는 2개의 개행 문자가 포함되어 있습니다. 첫 번째는 printf올바르게 인쇄됩니다. 그런 다음 두 번째는 평가를 통해 정확히 동일한 결과를 printf인쇄하고 할당합니다. S마지막 세 번째 쇼T$(...)printf마지막 개행 문자가 누락되었습니다 T! 왜?

sh, ksh 및 Zsh를 사용하여 동일한 결과를 얻었습니다.

답변1

이는 문서화된 동작입니다 man bash.

Bash는 하위 쉘 환경에서 명령을 실행하고 명령 대체를 명령의 표준 출력으로 바꾸고 후행 줄 바꿈을 제거하여 확장을 수행합니다.

물론, "왜?"라는 질문에 대한 답이 아니라고 말할 수도 있습니다.

공식적인 설명은 모르겠습니다. 내 생각에는 이것이 일반적으로 필요한 것이므로 이것이 의미가 있다고 생각합니다. 개행 문자를 제거하는 것보다 추가하는 것이 더 쉽습니다.

# This is how people are used to print text
echo foo

# In the other scenario this would end in two newlines at the end
echo foo "$(whatever)"

# could behandled with echo -n or printf but who would consider that an improvement?

또 다른 이유는 일부 명령은 끝에 개행 문자를 추가하지만 다른 명령은 그렇지 않기 때문입니다. 이 동작은 사용자가 이 차이에 대해 신경 써야 하는 부담을 덜어줍니다.

이 효과를 피하십시오

실제 명령 출력을 얻으려면 다음을 수행할 수 있습니다.

T=$(whatever; echo x)
T_real="${T%x}"

답변2

왜? 쓸모 없는,표준에 그렇게 나와있으니까:

...명령 대체를 명령의 표준 출력으로 대체하여 대체 끝에서 하나 이상의 <newline> 문자 시퀀스를 제거합니다.

사실, 아마도 항상 이런 식으로 작동했기 때문일 것입니다(내가 아는 한 POSIX는 대부분 기존 동작을 인코딩하는 것에 관한 것입니다).

더 유용하게는 다음과 같이 할 수 있습니다.

echo "$(date +"%F %T") $(hostname): something happened..."

바꾸다

t=$(date +"%F %T")
t=${t%
}
h=$(hostname)
h=${h%
}
echo "$t $h: something happened..."

즉, 단일 값을 인쇄하는 대부분의 명령은 명령줄에서 사용자 친화적으로 만들기 위해 끝에 개행 문자를 인쇄할 것입니다. (쉘은 커서가 명령 다음 줄의 시작 부분에 있지 않다는 것을 감지할 필요가 없습니다. zsh는 감지하지만 대부분의 다른 사람들은 그렇지 않습니다.) 그러나 스크립트에서 값을 사용하여 수행하는 경우 다른 것, 개행 문자가 필요하지 않을 수도 있고 콘텐츠만 필요합니다. 이는 인쇄뿐만 아니라 특정 명령에 값을 인수로 전달하는 경우에도 적용됩니다.

일반적인 솔루션추가 문자를 추가하고 제거합니다.

foo=$(printf 'foo\n'; echo .)
foo=${foo%.}
echo "<$foo>"

printf또는 내부 명령 대체 만 있는 경우 printf -v가능한 경우 다음을 사용하십시오.

printf -v foo 'foo\n'

관련 정보