개행 문자가 포함된 문자열이 있습니다. 이 문자열의 모든 개행 문자를 두 개의 문자열 "\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_CORRECT
N
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 텍스트 유틸리티로 처리할 수 없습니다.