sed
음역( y///
)을 사용하여 한 문자 집합을 다른 문자 집합으로 바꾸고 싶습니다 .
이 프로그램을 사용하는 것뿐만 아니라 이것이 효과가 있기를 바랍니다 tr
.
$ echo '[]{}abc' | tr '[ab}' 'gefh'
g]{hefc
그러나 sed를 사용하여 동일한 작업을 수행하면 다음 오류가 표시됩니다.
$ echo '[]{}abc' | sed 'y/[ab}/gefh/'
sed: 1: "y/[ab}/gefh/": unbalanced brackets ([])
[
문자를 이스케이프 처리해야 한다고 예상했기 때문에 이는 의미가 있습니다 . 그러나 이 상황을 벗어나려고 하면 다음과 같은 다양한 오류가 발생합니다.
$ echo '[]{}abc' | sed 'y/\[ab}/gefh/'
sed: 1: "y/\[ab}/gefh/": transform strings are not the same length
현재 해결 방법은 (1) 그냥 사용 tr
하거나 (2) 이스케이프된 문자와 일치하는 것 외에는 아무것도 하지 않는 음역 오른쪽에 "더미 문자"를 삽입하는 것입니다.
$ echo '[]{}abc' | sed 'y/\[ab}/_gefh/'
g]{hefc
그러나 이는 불만족스럽고 의심스럽습니다. 예를 들어 \
입력 문자열 내부에 있는 경우에도 매우 안전하지 않습니다 .
$ echo '[]{}abc\' | sed 'y/\[ab}/_gefh/'
g]{hefc_
이스케이프 문자 자체를 번역의 일부로 고려하지 않고 sed 음역에서 문자를 이스케이프하는 올바른 방법은 무엇입니까?
답변1
sed
macOS를 사용한다고 가정합니다(macOS용 FreeBSD가 어디에서 왔는지는 확인하지 않았지만 이 문제를 기본적으로 표시할 수 있는 유일한 시스템입니다 sed
).
$ echo '[]{}abc' | sed 'y/[ab}/gefh/'
sed: 1: "y/[ab}/gefh/": unbalanced brackets ([])
$ echo '[]{}abc' | sed 'y/\[ab}/gefh/'
sed: 1: "y/\[ab}/gefh/": transform strings are not the same length
$ echo '[]{}abc' | sed 'y/\[ab}/\gefh/'
g]{hefc
그래서,하나해결책은
[
불균형한 괄호를 피하기 위해 첫 번째 문자열을 이스케이프 처리 하고- 두 번째 문자열에 "no-op" 백슬래시를 추가하여 두 문자열의 길이를 동일하게 만듭니다.
또는,
두 문자열을 모두 로 감쌀 수도 있습니다
[...]
. 이는 문자열의 어디에 있는지 신경 쓰지 않고 기계적으로 수행할 수 있기 때문에 이를 처리하는 가장 안전한 방법일 것입니다[
.$ echo '[]{}abc' | sed 'y/[[ab}]/[gefh]/' g]{hefc
sed
아니면 macOS에 Homebrew나 FreeBSD의 패키지 시스템을 통해 GNU를 설치해서 사용하세요.
sed
나는 이것을 이 구현의 버그라고 생각합니다 .
답변2
당신이 하고 있는 일은 올바른 방법입니다. [
sed 에서는 항상 일반 문자여야 합니다 y///
. 이는 다음과 같은 문자 클래스의 tr
일부가 되는 것과는 다릅니다 .[
[:alpha:]
불행하게도 sed의 여러 구현에는 sed에서 균형 잡힌 괄호를 구문 분석하려고 시도하게 만드는 버그가 있는 것 같습니다. 나는 FreeBSD 11.2와 BusyBox 1.30.1에서 당신이 설명하는 버그를 관찰했습니다.
백슬래시 작업은 까다롭습니다. 백슬래시+문자의 동작은 그렇지 않습니다.기준문자가 \
, n
또는 구분 기호가 아닌 경우. 따라서 특정 구현에서 버그를 해결하는 데 이를 사용할 수 있지만 생성된 코드는 다른 구현에서는 작동하지 않을 수 있습니다.
이식 가능한 해결 방법은 [
변경하고 싶지 않은 다른 문자로 일시적으로 바꾸고 동일한 대체에서 자체적으로 변환하는 것입니다 ]
. 잘못된 구문 분석을 방지하려면 이 문자가 ]
, ^
또는 이 아니어야 합니다 :
. 교환을 수행할 때 대괄호와 그 사이에 있는 내용을 사용하여 문자열을 구성해야 합니다. FreeBSD는 대체를 좋아하지 않습니다 []
. 이를 해결하는 간단한 방법은 앞에 추가 문자를 추가하는 것입니다 ]
. 예를 들어 B
임시 [
.
y/[B_]/B[_]/; y/Bab}/gefh/; y/[B_]/B[_]/