-지

-지

-zsed를 사용하면 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 명령은 foowith 의 두 번째(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.

-지

이제 -zif를 사용하면 줄이 \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가 \0a를 때로는 구분 기호로 처리하고 \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하고 여러 번 일치하며 gslurp 내에서 일치하도록 m돕고 카운터 변수가 2일 때만 평가합니다.^ebar

답변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

관련 정보