-z
sed를 사용하면 null 데이터 패턴( )을 사용하여 n번째 패턴 발생을 일치시킬 수 있다는 것을 배웠습니다 sed -z 's/foo/bar/2'
.
을 사용할 때 줄의 시작 부분을 일치시키는 방법은 무엇입니까 -z
?
내가 실행하는 경우:
echo $'foo\nfoo\nfoo' | sed -z 's/^foo/baz/2'
^
전체 문자열의 시작 부분이 표시되므로 대체가 없습니다 .
$ echo $'foo\nfoo\nfoo' | sed -z 's/^foo/baz/g'
baz
foo
foo
Perl에는 다음이 있습니다.m
정규식 수정자(소리를 낼 때) 하지만 sed에서는 도움이 되지 않습니다.
답변1
echo $'foo\nfoo\nfoo' | sed -Ez 's/(^|\n)foo/\1baz/2'
^
첫 번째 줄의 시작 부분에 무엇이 발생하는지 정확하게 계산해야 합니다 foo
.
코드에서는 (^|\n)foo
가 아닌 의 발생 횟수를 계산합니다 foo
. s를 계산하고 싶지만 foo
교체하려는 경우오직원하는 항목이 줄의 시작 부분에 발생하면 이 코드는 해결책이 아닙니다. 예를 들어:
echo $'foo foo\nfoo foo\nfoo foo' | sed -Ez 's/(^|\n)foo/\1baz/3'
그가 교체된 것은 foo
이번이 세 번째가 아니다 foo
.
GNU 4.8을 사용하여 sed
테스트되었습니다 .
답변2
선택한 답변이 보이는 것처럼 간단하지 않습니다. 첫째, 2
(또는 s///2의 다른 숫자)는 실제로 무엇을 의미합니까? 이는 적용되는 줄의 두 번째 정규식 일치가 변경된다는 의미입니다.
존재하다
$ printf '%s\n' 'foo foo foo' 'foo foo foo' 'foo foo foo' | sed 's/foo/bar/2'
foo bar foo
foo bar foo
foo bar foo
sed 명령은 foo
with 의 두 번째(2) 인스턴스를 변경합니다 bar
.각적용되는 행(모든 행) 한 줄 또는 여러 줄에서만 작동하도록 변경할 수 있습니다.
printf '%printf '%s\n' 'foo foo foo'{,,,,} | sed '3,4s/foo/bar/2'
foo foo foo
foo foo foo
foo bar foo
foo bar foo
foo foo foo
전체 행이 아닌 행 3
합계 만 4
변경되며, 이러한 모든 행 중에서 foo
변경되는 인스턴스는 두 번째 행(2)입니다.
이것이 작동하는 방식입니다 s/foo/bar/2
.
-지
이제 -z
if를 사용하면 줄이 \0
(not \n
)로 끝납니다. 그러나 대체는 정확히 같은 방식으로 작동합니다( \0
대체 사용 \n
).
$ printf '%s\0' 'foo foo foo'{,,,,} | sed -z '3,4s/foo/bar/2' | xxd
00000000: 666f 6f20 666f 6f20 666f 6f00 666f 6f20 foo foo foo.foo
00000010: 666f 6f20 666f 6f00 666f 6f20 6261 7220 foo foo.foo bar
00000020: 666f 6f00 666f 6f20 6261 7220 666f 6f00 foo.foo bar foo.
00000030: 666f 6f20 666f 6f20 666f 6f00 foo foo foo.
\0과 \n을 혼합하세요.
거기 엔 echo $'foo\nfoo\nfoo' | sed -z 's/^foo/baz/2'
충분하지 않아foo
각 라인두 번째 것을 변경할 수 있지만 다음 예에서는 변경해야 합니까?
$ printf 'foo foo foo\nfoo foo foo\n' | sed -z 's/^foo/baz/2'
foo foo foo
foo foo foo
foo
이런, 아니, 처음에도 부족해요. 문제는 라인이 어디서 시작되는가입니다. 줄 바꿈이나 a \0
또는 둘 다에 있습니까? 아니면?
^
"-z"를 사용할 때 "줄의 시작"을 고려하는 것은 의미가 없습니다.
이것은 sed의 내부 혼란입니다. 기억하세요: 사용법 -z
은 실험적이며 이상한 문제가 발생할 수 있습니다.
패턴 공간
실제로 대체가 올바르게 작동하려면 전체 입력이 패턴 공간에 있어야 합니다. 아니요, 입력에 NUL( )이 있는 경우 아무런 효과가 없습니다. \0
이는 줄 구분 기호(또는 awk 용어로 레코드 구분 기호)로 처리됩니다.
$ printf 'foo\0foo\0foo\0' | sed -z 's/^foo/baz/2'
foofoofoo
sed의 패턴 공간 내에서 전체 입력 파일을 사용한 H;1h;$!d;x;.....
다음 ^foo
교체를 시도할 수 있습니다.
$ printf 'foo\0foo\0foo\0\n' | sed -z 'H;1h;$!d;x;l;s/^foo/ baz /M2'
foo\000foo\000foo\000\n$foo baz foo
l
패턴 공간 내부에 무엇이 있는지 볼 수 있게 하며 첫 번째 줄보다 더 많이 일치 M
하려면 이 플래그가 필요합니다 . 사용하지 않으면 ^
첫 번째 줄(패턴 공간의 시작 부분)만 일치합니다.M
^foo
대안은 다음 M
과 같습니다:
$ printf 'foo\0foo\0foo\0' | sed -z 'H;1h;$!d;x;l;s/\(^\|\x0\)foo/ baz /2'
foo\000foo\000foo$foo baz foo
입력에 명시적으로 제공된 후행이 부족한 \0
내부 패턴 공간에 입력하면 후행이 제거됩니다.foo\000foo\000foo
\0
\0
후행 줄 바꿈을 추가하여 세 가지를 모두 얻을 수 있습니다 .
$ printf 'foo\0foo\0foo\0\n' | sed -z 'H;1h;$!d;x;l;s/\(^\|\x0\)foo/ baz /2'
foo\000foo\000foo\000\n$foo baz foo
이는 sed가 \0
a를 때로는 구분 기호로 처리하고 \n
다른 경우에는 a를 구분 기호로 처리한다는 것을 분명히 보여줍니다.
간단히 말해서, -z
이 옵션을 사용한 sed는 아직 실험적입니다.
답변3
Perl에는 (후루룩 소리를 낼 때) 정규식 수정자가 있지만
m
도움이 되지 않습니다.
확신하는.
printf '%s\n' foo foo foo |\
perl -0777 -pe 's/^(foo)/++$c == 2 ? "bar" : $1/egm'
우리는 slurp를 사용 -0777
하고 여러 번 일치하며 g
slurp 내에서 일치하도록 m
돕고 카운터 변수가 2일 때만 평가합니다.^
e
bar
답변4
slurp 모드(-z)에서 GNU sed는 레코드 구분 기호를 null 값으로 처리합니다. 그러나 ASCII 텍스트 파일에는 널 문자가 없기 때문에 전체 파일은 본질적으로 sed의 레코드 또는 라인입니다. 이 문제를 해결하려면 먼저 모든 개행 문자(\n)를 줄 구분 기호(NUL)로 변경한 다음 두 번째 일치 항목에 s/// in t 여러 줄 패턴을 적용합니다. 마지막으로 역변환을 수행합니다.
printf '%s\n' foo foo foo |
sed -z '
y/\n/\x00/
s/^foo/BAR/M2
y/\x00/\n/
'
산출:
foo
BAR
foo