문서:
1
2
3
4
1
5
6
7
4
1
문자열(이 경우 )을 검색한 후 다음 문자열을 4
로 변경하고 싶습니다 8
.
예상 출력:
1
2
3
8
1
5
6
7
4
나는 시도했다:
cat file | sed '/1/ s/4/8/'
하지만 이는 해당 줄에서 변경될 문자열을 찾습니다.
또한 첫 번째 문자열과 두 번째 문자열 사이에 줄 수가 다를 수 있으므로 원본 파일을 줄 번호로 바꿀 수 없습니다.
GNU sed가 설치되어 있지 않습니다.
답변1
이것POSIX 특정 파일 편집기,ex
, 바로 그렇게 할 수 있습니다.
printf '%s\n' '/1//4/s//8/' x | ex file.txt
ex
여러 주소를 결합하는 기능. 따라서 /1/
이는 "정규식과 일치하는 다음 줄로 이동"(또는 인용)하는 것을 의미합니다 1
. 그럼 /4/
가그 라인에서다음 줄과 일치합니다 4
. s//8/
Sed에서와 같이 일반적인 의미를 가지며, 명령 s
에 전달된 빈 정규식은 "마지막으로 사용한 정규식 재사용"을 의미하며, 이 경우에는 입니다 4
.
변경 사항을 저장하지 않고 수정된 파일을 인쇄하려면 대신 다음 명령을 사용하십시오.
printf '%s\n' '/1//4/s//8/' %p | ex file.txt
여러 주소를 더 잘 이해하기 위해 다음 명령은 다음을 포함하는 첫 번째 줄을 제거합니다.cherry
앞으로첫 번째 줄에는 다음이 포함됩니다.banana
뒤쪽에27행:
printf '%s\n' '27/banana/?cherry?d' x | ex file.txt
x
변경 사항을 저장하고 종료한다는 의미는 %p
"전체 파일 인쇄"를 의미합니다. ( 첫 번째 줄부터 마지막 줄까지의 주소 범위인 %
yes 의 동의어 입니다.)1,$
답변2
PATTERN
a 다음에 나오는 첫 번째 항목 만 바꾸려면 MARKER
다음을 수행하세요.
sed '/MARKER/,${
/PATTERN/{
x
//{
x
b
}
g
s/PATTERN/REPLACEMENT/
}
}' infile
범위(파일의 처음 MARKER
부터 끝까지)를 사용하고 버퍼를 예약합니다. 일치하는 줄을 만날 때마다 PATTERN
버퍼를 바꾸고 예약된 공간의 줄도 일치하는지 확인합니다. 그렇다면 다시 바꾸고 스크립트 끝으로 이동합니다. 그렇지 않으면 덮어쓰고 현재 줄로 바꿉니다.
답변3
일반 솔루션을 사용하여 여러 s 및 s가 있는 awk
다음 수정된 입력 파일을 고려하십시오.1
4
$ cat ip.txt
1
foo
1
xyz
4
4
1
1
eeeee
4
1
rrrrrr
4
1
4
플래그를 사용하여 일치 항목을 나타내고 1
카운터를 사용하여 어떤 블록이 수정되고 있는지 알 수 있습니다. 일치 루프를 다시 시작하려면 플래그를 지워야 합니다.
$ # first block
$ awk '/1/{f=1} f && /4/{c++; f=0; if(c==1) $0="8"} 1' ip.txt
1
foo
1
xyz
8
4
1
1
eeeee
4
1
rrrrrr
4
1
4
$ # second block
$ awk '/1/{f=1} f && /4/{c++; f=0; if(c==2) $0="8"} 1' ip.txt
1
foo
1
xyz
4
4
1
1
eeeee
8
1
rrrrrr
4
1
4
첫 번째 블록만 변경하는 것으로 단순화 가능
awk '/1/{f=1} f && !c && /4/{c++; $0="8"} 1' ip.txt
답변4
awk를 사용하면 필요한 N번째 발생과 더 쉽고 호환됩니다.
awk '/pattern to search/{n+=1}{if (n==OCCURRENCE){sub("PATTERN","SUBSTITUTE",$0)};print }' FILE-NAME
예:
-bash-4.4$ cat toto
1
2
3
4
5
6
1
2
3
4
5
6
1
2
3
4
-bash-4.4$ awk '/4/{n+=1}{if (n==2){sub("4","---8",$0)};print }' toto
1
2
3
4
5
6
1
2
3
---8
5
6
1
2
3
4
-bash-4.4$
첫 번째나 마지막이 아닌 두 번째 4개만 변경되었습니다.