단순화하기 위해 패턴을 일치시킨 후 전체 파일을 편집하고 싶습니다. 파일 예는 다음과 같습니다.
$ cat file
ip=x.x.x.a
mask=255.0.0.0
host=a
ip=x.x.x.b
mask=255.0.0.0
host=b
ip=x.x.x.c
mask=255.0.0.0
host=c
ip=x.x.x.x
blahblah
mask=255.0.0.0
host=d
호스트 c의 IP를 편집하고 싶지만 변수가 있을 수 있으므로 값을 모른다고 가정해 보겠습니다. 해당 줄을 인쇄하는 grep host c
데 사용 하면 -B2
원본 파일에서 편집할 수 없습니다! 또 다른 점은 행이 호스트 d의 경우와 같은 구조를 갖지 않을 수 있다는 것입니다. ip
와 mask
정보 사이에 일부 텍스트가 있으므로 IP 패턴이 항상 내 검색 패턴보다 2줄 앞선다고 가정할 수 없습니다.
계속해서 IP를 모르기 때문에 직접 grep할 수는 없지만 대신 호스트를 검색하고 이 일치 전에 행을 편집하여 IP 값을 변경해야 합니다. 어떻게 해야 하나요?
답변1
파일을 뒤로 탐색하면 훨씬 쉬워집니다. 다행히도 이 작업은 쉽게 수행할 수 있습니다 tac
(역방향 작업임 cat
). 그런 다음 비교적 간단한 awk
스크립트를 사용하여 원하는 스크립트를 찾아 host
변경할 수 있습니다 ip
.
$ tac input | awk -v OFS="=" -v myip="changed_address" -v myhost="d" -F"=" '$1 == "host" { if( $2 == myhost ) { sw = "on" } else { sw="off" } } sw == "on" && $1 == "ip" { $2=myip } { print $0 }' | tac
ip=x.x.x.a
mask=255.0.0.0
host=a
ip=x.x.x.b
mask=255.0.0.0
host=b
ip=x.x.x.c
mask=255.0.0.0
host=c
ip=changed_address
blahblah
mask=255.0.0.0
host=d
awk
어떻게 작동하는지 자세히 설명하겠습니다 .
먼저 몇 가지 변수를 선언합니다. 각 변수는 for host
이고 새 값은 다음과 같습니다 ip
.
-v myip="changed_address" -v myhost="d"
또한 입력 및 출력에 대한 필드 구분 기호를 선언합니다.
-v OFS="=" -F"="
이제 실제 awk
스크립트 자체는 다음과 같습니다.
$1 == "host" { // If we see the "host" line..
if( $2 == myhost ) { // And it matches the one we're looking for..
sw = "on" // Set a flag to swap the next IP
} else {
sw="off" // Otherwise, unset the flag
}
}
sw == "on" && $1 == "ip" { // If the flag is set and this is an IP line..
$2=myip // Swap in the new IP
}
{
print $0 // Finally, print out the processed line
}
모든 작업이 완료되면 tac
다시 사용하여 되돌리고 앞으로 다시 이동합니다.
답변2
그러면 호스트와 연결된 IP가 c
다음으로 변경됩니다 1.2.3.4
.
$ sed 's/^ip/\nip/' file | perl -00pe 'if(/\nhost=c\n/){s/ip=\S+/ip=1.2.3.4/} s/\n\n/\n/'
ip=x.x.x.a
mask=255.0.0.0
host=a
ip=x.x.x.b
mask=255.0.0.0
host=b
ip=1.2.3.4
mask=255.0.0.0
host=c
ip=x.x.x.x
blahblah
mask=255.0.0.0
host=d
설명하다:
sed 's/^ip/\nip/' file
\n
:로 시작하는 각 줄에 추가 개행 문자( )를 추가합니다ip
. 나는 이것이 의 모든 구현에서 작동하지 않을 수 있다고 생각하므로sed
, 당신의 구현이 이것을 지원하지 않는다면sed
명령을 로 바꾸십시오perl -pe 's/^ip/\nip/'
. Perl의 "단락 모드"(아래 참조)를 사용하려면 이것이 필요합니다.perl -00pe
:-00
Perl이 "단락 모드"에서 실행되도록 합니다. 여기서 "줄"은 두 개의 연속적인 개행으로 정의됩니다. 이를 통해 각 호스트의 블록을 "라인"으로 처리할 수 있습니다.-pe
"주어진 스크립트를 적용한 후 각 줄을 인쇄합니다 " 를 의미합니다-e
.if(/\nhost=c\n/){s/ip=\S+/ip=1.2.3.4/}
: 이 "라인"(부분)이 개행 문자와 일치하고 그 뒤에 문자열이 온host=c
다음 또 다른 개행 문자가 오는 경우ip=
이를 공백이 아닌 문자( ) 1개 이상으로 바꿉니다.\S+
ip=1.2.3.4
s/\n\n/\n/
각 개행 문자 쌍을 단일 개행 문자로 대체하여 원본 파일의 형식을 복원합니다.
파일을 변경하려면 다음을 사용할 수 있습니다.
tmp=$(mktemp); sed 's/^ip/\nip/' file > $tmp;
perl -00pe 'if(/\nhost=c\n/){s/ip=\S+/ip=1.2.3.4/} s/\n\n/\n/' $tmp > file
답변3
또 다른 옵션은 다음 주소로 몇 가지 명령을 보내는 것입니다 ed
.
h=c
ed -s file <<< $'/^host='"${h}"$'$\n?^ip=\nc\nip=new.ip.here\n.\nw\nq' > /dev/null
기본 아이디어는 개행으로 구분된 명령 목록(ANSI C 인용 문자열 두 개)에서 파일과 파이프를 편집하고, $' ... '
주어진 호스트(변수에서 $h
)를 검색한 다음 ip=
Make it new로 시작하는 줄을 역방향으로 검색한 다음 저장하는 것입니다. 그리고 종료합니다 ed
. 줄 바꿈( )으로 구분된 \n
명령은 다음과 같습니다.
/^host=
...$h
$
-- ( ) 행으로 시작하는 문자열 검색을 시작하고 ( )/
내용을 검색한 다음 마지막으로 ( ) 행의 끝을 검색합니다. 호스트가 정확히 일치하지 않는 경우 줄 끝 요구 사항을 완화하세요.host=
^
$h
$
?^ip=
-- 이제 일치하는 줄에 있으므로ip=
줄의 시작 부분에 있는 텍스트를 거꾸로 검색합니다.c
-- 이 줄을 바꾸세요텍스트 삽입
ip=new.ip.here
.
-- 삽입된 텍스트 끝w
--디스크에 파일 쓰기q
——편집 종료
-s
파일을 열고 저장할 때 방출되는 바이트 수를 묵음 으로 호출하여 ed를 호출합니다 . 검색 중인 및 행이 발견되면 전체 명령을 리디렉션하여 /dev/null
기본 출력을 무음으로 설정합니다.ed
host=
ip=
답변4
$ awk -v host=c -v newip=zzz.zzz.zzz.zzz '$0 ~ "^host=" host "$" { print; getline; $0 = sprintf("ip=%s\s", newip) }; 1' file
ip=x.x.x.a
mask=255.0.0.0
host=a
ip=x.x.x.b
mask=255.0.0.0
host=b
ip=x.x.x.c
mask=255.0.0.0
host=c
ip=zzz.zzz.zzz.zzzs
blahblah
mask=255.0.0.0
host=d
이는 특정 호스트의 IP 주소를 변경하려고 하며 IP 주소 줄이 항상 host=
해당 호스트의 줄 뒤에 나타난다고 가정합니다.
프로그램은 awk
두 개의 변수와 를 설정하여 명령줄에서 호스트 이름과 새 IP 주소를 얻습니다. 그런 다음 코드는 지정된 호스트 이름에 해당하는 행을 찾고 다음 행(해당 행)을 읽고 삭제한 다음 새 IP 주소를 사용하여 새 행을 만듭니다. 데이터(수정되거나 수정되지 않은)는 프로그램의 꼬리에 의해 출력됩니다.awk
host
newip
host=
ip=
ip=
1