나는 sed를 배우고 있습니다. N(다음에 여러 줄)을 누르기 전까지는 모든 것이 잘 진행되는 것 같습니다. 연습/이해/컨텍스트 목적으로 이 파일(guide.txt)을 만들었습니다. 파일 내용은 이렇습니다...
This guide is meant to walk you through a day as a Network
Administrator. By the end, hopefully you will be better
equipped to perform your duties as a Network Administrator
and maybe even enjoy being a Network Administrator that much more.
Network Administrator
Network Administrator
I'm a Network Administrator
따라서 내 목표는 "네트워크 관리자"의 모든 인스턴스를 "시스템 사용자"로 바꾸는 것입니다. "Network Admin"의 첫 번째 인스턴스는 줄 바꿈(\n)으로 구분되므로 "Admin"으로 시작하고 "Network\n"으로 끝나는 줄을 이전 행에 추가하려면 여러 줄의 다음 연산자(N)가 필요합니다. 괜찮아요. 하지만 다른 모든 "Network Manager" 단일 인스턴스도 캡처하고 싶습니다.
내 연구에 따르면 개행으로 구분된 문자열에 대해 하나, 다른 문자열에 대해 하나라는 두 개의 대체 명령이 필요하다는 것을 알고 있습니다. 또한 마지막 줄에 대체 일치 항목과 다음 여러 줄이 포함되어 있으므로 일부 자이브가 발생합니다. 그래서 이걸 만들었어요...
$ sed '
> s/Network Administrator/System User/
> N
> s/Network\nAdministrator/System\nUser/
> ' guide.txt
그러면 다음 결과가 반환됩니다...
This guide is meant to walk you through a day as a System
User. By the end, hopefully you will be better
equipped to perform your duties as a System User
and maybe even enjoy being a Network Administrator that much more.
System User
Network Administrator
I'm a System User
나는 한 줄 바꾸기가 "네트워크 관리자"의 모든 "일반" 인스턴스를 캡처하여 "시스템 사용자"로 바꿀 것이라고 생각했으며 여러 줄 문은 개행으로 구분된 인스턴스에서 마법을 작동할 것이라고 생각했지만 보시다시피 반환됨을 고려했습니다. 예상치 못한 결과.
좀 헤매다가 이걸 발견했습니다...
$ sed '
> s/Network Administrator/System User/
> N
> s/Network\nAdministrator/System\nUser/
> s/Network Administrator/System User/
> ' guide.txt
자, 보라, 나는 원하는 결과를 얻었습니다 ...
This guide is meant to walk you through a day as a System
User. By the end, hopefully you will be better
equipped to perform your duties as a System User
and maybe even enjoy being a System User that much more.
System User
System User
I'm a System User
왜 이것이 작동하지만 원래 sed 스크립트는 작동하지 않습니까? 나는 이것을 정말로 이해하고 싶습니다.
도움을 주셔서 미리 감사드립니다.
답변1
먼저 귀하의 솔루션이 실제로 작동하지 않는다는 점에 유의하십시오. 다음 테스트 파일을 고려해보세요.
$ cat test1
Network
Administrator Network
Administrator
그런 다음 다음 명령을 실행합니다.
$ sed '
s/Network Administrator/System User/
N
s/Network\nAdministrator/System\nUser/
s/Network Administrator/System User/
' test1
System
User Network
Administrator
문제는 코드가 마지막 코드를 대체하지 않는다는 것입니다 Network\nAdministrator
.
이 솔루션은 작동합니다.
$ sed ':a; /Network$/{$!{N;ba}}; s/Network\nAdministrator/System\nUser/g; s/Network Administrator/System User/g' test1
System
User System
User
우리는 이것을 다음에도 적용할 수 있습니다 guide.txt
:
$ sed ':a; /Network$/{$!{N;ba}}; s/Network\nAdministrator/System\nUser/g; s/Network Administrator/System User/g' guide.txt
This guide is meant to walk you through a day as a System
User. By the end, hopefully you will be better
equipped to perform your duties as a System User
and maybe even enjoy being a System User that much more.
System User
System User
I'm a System User
핵심은 요구 사항에 맞는 것을 찾을 때까지 한 줄씩 계속 읽는 것입니다.아니요완료 Network
되면 교체할 수 있습니다.
호환성 참고 사항:위의 내용은 모두 \n
대체 텍스트에 사용됩니다. 이를 위해서는 GNU sed가 필요합니다. BSD/OSX sed에서는 작동하지 않습니다.
[쪽으로필립스.]
여러 줄 버전
이해하는 데 도움이 된다면 동일한 명령을 여러 줄로 나누어서 설명하겠습니다.
$ sed ':a
/Network$/{
$!{
N
ba
}
}
s/Network\nAdministrator/System\nUser/g
s/Network Administrator/System User/g
' filename
어떻게 작동하나요?
:a
그러면 라벨이 생성됩니다
a
./Network$/{ $!{N;ba} }
줄이 로 끝나면
Network
다음과 같습니다.아니요마지막 줄($!
)은 다음 줄(N
)을 읽고 추가하고 레이블a
(ba
)로 다시 분기됩니다.s/Network\nAdministrator/System\nUser/g
중간 개행 문자로 바꾸세요.
s/Network Administrator/System User/g
중간 공백으로 교체합니다.
더 간단한 솔루션(GNU에만 해당)
GNU sed 사용(아니요BSD/OSX), 대체 명령만 필요합니다:
$ sed -zE 's/Network([[:space:]]+)Administrator/System\1User/g' test1
System
User System
User
그리고 guide.txt
파일에:
$ sed -zE 's/Network([[:space:]]+)Administrator/System\1User/g' guide.txt
This guide is meant to walk you through a day as a System
User. By the end, hopefully you will be better
equipped to perform your duties as a System User
and maybe even enjoy being a System User that much more.
System User
System User
I'm a System User
이 예에서는 -z
sed에게 첫 번째 NUL 문자를 읽도록 지시합니다. 텍스트 파일에는 null 문자가 포함될 수 없으므로 전체 파일을 한 번에 읽는 효과가 있습니다. 그러면 행을 잃을 염려 없이 대체를 수행할 수 있습니다.
파일이 큰 경우(일반적으로 기가바이트를 의미함) 이 방법은 적합하지 않습니다. 너무 큰 경우 한 번에 모두 읽으면 시스템 RAM에 부담을 줄 수 있습니다.
GNU 및 BSD sed용 솔루션
제안대로필리포스, 휴대용 솔루션은 다음과 같습니다.
sed 'H;1h;$!d;x;s/Network\([[:space:]]\)Administrator/System\1User/g'
답변2
그 동안 sed
시간을 내어 @John1024의 답변에 추가하겠습니다.
\n
1) 대체 문자열에 무엇을 사용하고 있는지 확인하십시오. 이것은 GNU에서 작동 sed
하지만 POSIX의 일부가 아니므로 n
다른 많은 s sed
에 백슬래시와 an을 삽입 합니다( \n
그런데 패턴에서 사용할 때 이식 가능합니다).
대신에 다음을 권장합니다 s/Network\([[:space:]]\)Administrator/System\1User/g
. [[:space:]]
개행이나 공백과 일치하므로 두 개의 s
명령이 필요하지 않고 하나로 병합합니다. 다음으로 둘러싸 \(...\)
대체 항목에서 참조할 수 있습니다 . \1
첫 번째 쌍에서 일치하는 항목으로 대체됩니다 \(\)
.
2) 두 줄의 패턴을 올바르게 일치시키려면 패턴을 알아야 합니다 N;P;D
.
sed '$!N;s/Network\([[:space:]]\)Administrator/System\1User/g;P;D'
항상 N
다음 줄을 추가합니다(마지막 줄을 제외하고 이것이 "주소가 지정된" 이유입니다 $!
(= 마지막 줄이 아닌 경우; 실수로 스크립트를 종료하지 않도록 항상 계속 고려해야 합니다). 그런 다음 교체 후에는 N
첫 번째 줄만 인쇄합니다. 패턴 공간 한 줄에서 해당 줄을 제거하고 원래 의도였던 나머지 패턴 공간(다음 줄을 읽지 않고)을 사용하여 다음 루프를 시작합니다.$!
P
D
이 패턴을 기억하세요. 자주 필요할 것입니다.
3) 여러 줄 편집을 위한 또 다른 유용한 패턴, 특히 두 줄 이상이 관련된 경우: John에게 제안한 것처럼 공간을 모아 두십시오.
sed 'H;1h;$!d;g;s/Network\([[:space:]]\)Administrator/System\1User/g'
설명을 위해 반복하겠습니다. H
각 행을 예약된 공간에 추가합니다. 이로 인해 첫 번째 줄 앞에 추가 개행이 발생하므로 첫 번째 줄을 추가하는 대신 이동해야 합니다 1h
. 다음은 $!d
"마지막 줄을 제외한 모든 줄에 대해 패턴 공간을 제거하고 다시 시작"을 의미합니다. 따라서 나머지 스크립트는 마지막 줄에 대해서만 실행됩니다. 이때 전체 파일은 예약된 공간에 모아져(매우 큰 파일에는 사용하지 마세요!) 패턴 공간으로 이동되므로 GNU 옵션을 사용하는 것처럼 g
한번에 모든 교체를 수행 할 수 있습니다 .-z
sed
이는 제가 기억해두기를 권장하는 또 다른 유용한 패턴입니다.