다음과 같은 파일이 있습니다 swap
.
$ cat swap
aardvark BILL CLINTON dog
eternal CLINTON BILL forever
BILL good housekeeping BILL
BILL
to 의 모든 항목을 변경하고 to CLINTON
의 모든 항목을 동시에 변경하고 싶습니다 . 결과 출력은 다음과 같습니다.CLINTON
BILL
aardvark CLINTON BILL dog
eternal BILL CLINTON forever
CLINTON good housekeeping CLINTON
나는 고전적인 해결책을 알고 있습니다.
sed -e 's/BILL/temp/g' -e 's/CLINTON/BILL/g' -e 's/temp/CLINTON/g'
그러나 누군가가 나에게 연습 차원에서 세 번째 단어를 사용하지 말라고 도전했습니다.
다음 명령을 사용하고 있지만 첫 번째 줄에서만 작동합니다.
$ sed 's/\(BILL\) \(CLINTON\)/\2 \1/g' swap
aardvark CLINTON BILL dog
eternal CLINTON BILL forever
BILL good housekeeping BILL
참고: 저는 Solaris 10 운영 체제를 사용하고 있습니다.
이 인위적인 제약을 관찰하면서 어떻게 원하는 출력을 얻을 수 있습니까?
행동
MORBILLIFORM OVERBILLED
TOM, BILL, AND HARRISON
명시되지 않은.
답변1
perl -pe 's/(BILL)|CLINTON/$1 ? "CLINTON" : "BILL"/eg' swap
설명하다:
-p
옵션을 사용하면 Perl
파일 la가 awk
한 줄씩 읽혀지고 모든 변환이 적용된 후 현재 레코드가 자동으로 인쇄됩니다.
이 s///
명령은 현재 줄에서 작동합니다. 패턴 /eg
수정자는 다음과 같습니다. /g
변환을 첫 번째 줄로 제한하는 대신 현재 줄에 전역적으로 변환을 적용합니다( 언급하지 않은 경우 .) 는 변환을 코드 로 처리 하는 /g
-uate /e
수정자 입니다. 평가 후 결과 값은 RHS로 간주됩니다.eval
RHS
s///
Perl
따라서 s/(BILL)|CLINTON/.../은 왼쪽부터 스캔하여 현재 레코드에서 BILL 또는 CLINTON을 찾습니다. BILL이 발견되면 $1이 설정되므로 Perl 표현식 $1 ? "CLINTON" : "BILL"은 현재 레코드에서 BILL이 대체되는 CLINTON으로 평가됩니다. 하지만 수정자 덕분에 우리는 끝났습니다 /g
. 마찬가지로, CLINTON이 발견되면 $1은 비어 있으므로 Perl 표현식 $1 ? "CLINTON" : "BILL"은 현재 레코드의 끝에 도달할 때까지 이 레코드에 CLINTON인 BILL로 평가됩니다 -p
. STDOUT으로 인쇄됩니다.
sed -e 's/BILL\|CLINTON/\n&/g;s/\nBILL/CLINTON/g;s/\nCLINTON/BILL/g' swap
답변2
앗해결책:
awk '{ for(i=1;i<=NF;i++) { if($i=="BILL") $i="CLINTON"; else if($i=="CLINTON") $i="BILL" } }1' swap
산출:
CLINTON BILL
BILL CLINTON
CLINTON CLINTON
for(i=1;i<=NF;i++)
- 모든 필드에 대해 반복(앗공백을 기본 필드 구분 기호로 처리)if($i=="BILL") $i="CLINTON"
- 필드 값이 동일한 경우BILL
- 할당CLINTON
else if($i=="CLINTON") $i="BILL"
- 그렇지 않은 경우 필드 값이 동일하면CLINTON
- 이를 다음에 할당합니다.BILL
답변3
또 다른 awk 솔루션
awk '{
while (match($0, /BILL|CLINTON/)) {
printf "%s", substr($0, 1, RSTART-1);
$0 = substr($0, RSTART);
printf "%s", /^BILL/ ? "CLINTON" : "BILL";
$0 = substr($0, 1+RLENGTH)
}
print
}' swap