POSIX sh 문자열의 모든 개행 문자를 "\n"으로 변환하는 방법

POSIX sh 문자열의 모든 개행 문자를 "\n"으로 변환하는 방법

개행 문자가 포함된 문자열이 있습니다. 이 문자열의 모든 개행 문자를 두 개의 문자열 "\n"으로 대체하여 이스케이프하고 싶습니다. POSIX sh에서 이 작업을 어떻게 수행할 수 있나요?

목표는 다음과 같습니다.

$ printf 'a\nb\nc\nd' | escape_newlines | od -a
0000000   a   \   n   b   \   n   c   \   n   d
        141 134 156 142 134 156 143 134 156 144
0000012

그걸 어떻게 정의하나요 escape_newlines?

내가 시도한 것:

  • tr— 문제: 단일 문자를 여러 문자로 변환할 수 없습니다.

  • awk 'BEGIN{ORS="\\n"} {print}'— 문제: 문자열이 개행 문자로 끝나지 않는 경우에도 두 문자 문자열 "\n"이 항상 문자열 끝에 삽입됩니다. 예:

    $ printf 'hi\n' | awk 'BEGIN{ORS="\\n"} {print}' | od -ab
    0000000   h   i   \   n
            150 151 134 156
    0000004
    $ printf 'hi' | awk 'BEGIN{ORS="\\n"} {print}' | od -ab
    0000000   h   i   \   n
            150 151 134 156
    0000004
    
  • sed -e ':a' -e 'N' -e '$!ba' -e 's/\n/\\n/g'— 문제: 문자열 끝에 개행 문자가 있으면 변환되지 않습니다. 예:

    $ printf 'h\ni' | sed -e ':a' -e 'N' -e '$!ba' -e 's/\n/\\n/g' | od -ab
    0000000   h   \   n   i
            150 134 156 151
    0000004
    $ printf 'h\ni\n' | sed -e ':a' -e 'N' -e '$!ba' -e 's/\n/\\n/g' | od -ab
    0000000   h   \   n   i  nl
            150 134 156 151 012
    0000005
    

답변1

다음을 사용해 보세요 awk:

string='x
y
'
new_string=$(
  LC_ALL=C awk -- '
    BEGIN {
      gsub("\n", "\\n", ARGV[1])
      printf "%s", ARGV[1]
    }' "$string"
)

그럼에도 불구하고 명령 대체는 후행 줄 바꿈을 제거한다는 점에 유의하십시오. 의 출력에는 아무 것도 포함되어 있지 않으므로 여기서는 문제가 없습니다 . awk그러나 이는 print.printf "%s"

그리고 sed:

new_string=$(
  printf '%s\n' "$string" |
    LC_ALL=C sed '
      :1
      $ ! {
        N
        b1
      }
      s/\n/\\n/g'
)

POSIX에 따르면 N마지막 줄에 사용하는 것은 패턴 공간을 버리고 종료하는 것을 의미합니다. GNU는 환경에 있는 동안에만 이 작업을 수행 sed하지만 마지막 줄에서 호출되면 여전히 종료됩니다(그러나 여전히 패턴 공간을 인쇄합니다).$POSIXLY_CORRECTN

LC_ALL=C사용자 로케일의 문자 맵에서 문자열을 디코딩할 때 발생할 수 있는 문제를 방지하기 위해 이를 사용합니다 .

sed텍스트 유틸리티이므로 텍스트 입력을 받아 텍스트 출력을 생성합니다. 비어 있지 않고 개행 문자로 끝나지 않는 내용은 텍스트가 아닙니다. 여기서는 입력에 개행 문자를 추가하고 명령 대체를 사용하여 sed추가된 개행 문자를 출력에서 ​​제거합니다.

또한 입력 줄 길이가 LINE_MAX 바이트(1024만큼 낮을 수 있음)보다 길면 텍스트도 아닌 상태가 되며 동작이 지정되지 않습니다. IIRC에서는 패턴 공간이 10 x LINE_MAX 이상을 수용할 필요도 없습니다.

awk방법에는 ARG_MAX부터 시작하여 시스템의 10 x LINE_MAX보다 낮은 몇 가지 제한 사항도 있습니다. 이 제한사항은 내장되지 않은 쉘(예: ksh88 또는 pdksh 기반 쉘) sed에도 적용됩니다 .printf

셸 변수의 크기에는 제한이 없지만 환경으로 내보내지면 실행되는 모든 외부 명령에 대한 ARG_MAX 제한에 따라 실행됩니다.

스트림을 처리하려면 다음과 같은 것이 필요합니다.

... | (cat; echo) | LC_ALL=C awk '
  {printf "%s", sep $0; sep = "\\n"}'

그러나 출력은 텍스트가 아니므로 POSIX 텍스트 유틸리티로 처리할 수 없습니다.

관련 정보