POSIX 스크립트에서 큰따옴표를 인쇄하는 방법은 무엇입니까?

POSIX 스크립트에서 큰따옴표를 인쇄하는 방법은 무엇입니까?

지금까지 나는 다음을 "\""사용하여 큰따옴표를 인쇄해 왔습니다.

$ x="abc def"
$ echo "x=\"$x\""
x="abc def"

그러나 이 동작은 정의되지 않은 것 같습니까?

~을 위한echo https://pubs.opengroup.org/onlinepubs/9699919799/utilities/echo.html(XSI 호환 시스템의 추가 사양을 무시하면) 백슬래시는 완전히 정의되지 않은 동작으로 이어집니다.

표준 출력에 기록될 문자열입니다. 첫 번째 피연산자가 -n이거나 피연산자에 <backslash> 문자가 포함된 경우 결과는 구현에 따라 정의됩니다.

이 페이지는printf https://pubs.opengroup.org/onlinepubs/9699919799/utilities/printf.html주로 파일 형식 기호를 나타냅니다.https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap05.html#tag_05이것도 지원되지 않습니다 \".

다음 두 가지 방법은 어떻습니까? 명시적으로 POSIX를 준수합니까?

  • 연결 '"문자열

    $ x="abc def"
    $ printf x=%s\\n '"'"$x"'"'
    x="abc def"
    
  • 8진수 값 사용 ":

    $ x="abc def"
    $ printf x=\\42%s\\42\\n "$x"
    x="abc def"
    

대안은 무엇입니까?

답변1

예, 이 동작(사용법 \")은 POSIX에서 echo모든 곳이 아니라 명령에 대해 정의되지 않았습니다. 이것이 echo 대신 printf를 사용하는 이유 중 하나입니다. 읽어주세요왜 printf가 echo보다 나은가요?.

물론 여기에는 몇 가지 설명이 필요합니다.

A \"구현 정의그게 경우에만피연산자에코.

여기서 단어 정의는 얼마나 중요합니까? 명령줄에 작성하는 모든 내용은 여러 번 읽고 수정된 다음유틸리티에 피연산자로 제공됨. 우리가 명령줄 인수("단어")라고 부르는 것은 쉘에 의해 여러 가지 방법으로 변환됩니다. 마지막 변경 사항 중 하나는 "인용문 제거"입니다. 결국 이게 결과라면피연산자Contains 는 \"" echo올바른" 것으로 간주되는 모든 작업을 수행할 권리가 있습니다.

명령줄이 피연산자와 echo '\"'OR echo "\\\""로 연결된 경우 \"결과는 구현에 따라 정의됩니다.

귀하의 예 x="abc def"; echo "x=\"$x\""는 다음과 같습니다아니요구현에 따라 정의됩니다. echo에 의해 수신된 피연산자는 입니다 x="abc def". 하지만 변수의 내용에 따라 다릅니다 x.

그러한 것을 방지하려면가능한질문 피연산자가 무엇이든 관계없이 출력이 POSIX로 정의되므로 제한이 없는 printf를 사용해야 합니다.

따라서 큰따옴표를 인쇄하는 일반적인 솔루션은 printf 명령의 형식 부분에 이를 넣는 것입니다.

$ printf 'x="%s"\n' "$x"
x="abc def"

작은 따옴표를 인쇄해야 하는 경우 따옴표를 변경하거나 "따옴표 종료 - 작은 따옴표 넣기 - 따옴표 다시 시작"이라는 일반적인 트릭을 사용해야 합니다.

$ printf 'x='\''%s'\''\n' "$x"
x='abc def'

또는:

$ printf "x='%s'"'\n' "$x"
x='abc def'

또는 더 나은 방법은 작은 따옴표를 큰 따옴표로 묶은 문자열로 전환하는 것입니다.

$ printf 'x=%s\n' "'$x'"
x='abc def'

\ddd하지만 그렇습니다. printf는 8 진수를 지원하므로 ddd다음을 사용할 수도 있습니다.

$ printf 'x=\042%s\042\n' "$x"
x="abc def"

위의 모든 솔루션은 유효한 POSIX 구성입니다. 하나를 선택하십시오.

답변2

POSIX 셸에서 다음 명령을 실행해 보세요.

echo "abc"

에 명시된 규칙에 따라2.2.3 큰따옴표, "abc"은 큰따옴표이므로 큰따옴표 문자는 리터럴이 아니라 큰따옴표로 구성된 묶인 문자입니다. 따라서 첫 번째 인수 값으로 echo수신하지도 않습니다 ."abc"abc

또한 2.2.3 큰따옴표의 마지막 단락은 큰따옴표 안에 나타나는 백슬래시의 동작을 정의합니다. "및 일부 다른 문자의 경우 섹션 2.2에 정의된 "이스케이프 문자로서의 특별한 의미를 유지해야 합니다". . 해당 섹션에 따르면 이스케이프 문자는 "다음 문자의 리터럴 값"을 유지합니다.

이는 원래 질문을 제기한 원래 질문 텍스트의 첫 번째 예가 완벽하게 괜찮다는 것을 의미합니다.

$ x="abc def"
$ echo "x=\"$x\""
x="abc def"

echoPOSIX 쉘은 이미 백슬래시 문자를 이스케이프 문자로 사용하기 때문에 프로그램은 백슬래시 문자를 전혀 수신하지 않습니다 . 따라서 백슬래시가 매개변수 값에 나타나면 백슬래시가 없기 때문에 echo사양(또는 다른 프로그램)이 정의하는 내용은 중요하지 않습니다 .printf

물론 위의 내용은 모두 제한적이며 x위에서 설정한 값(및 기타 일부 제한된 값)에만 유효합니다. 값을 x다른 것으로 변경할 수 있는 경우 따옴표를 제거한 후 백슬래시를 포함할 수 있습니다 \. 이는 셸 명령줄 인수(셸 용어로 "단어")를 다음으로 변환합니다.피연산자존재하다유틸리티에 대한 POSIX의 말.

이로 인해 다음 내용이 echo구현 정의될 위험이 있습니다. printf그런 문제는 없습니다.

관련 정보