다음 텍스트 파일이 있습니다.
banana
apple
juice
mango
something
패턴을 검색 중인데 juice
일치하는 패턴의 두 번째 줄(즉, 일치하는 패턴 위의 두 줄)을 역순으로 찾아 로 바꾸려고 합니다 coconut
.
예상 출력:
coconut
apple
juice
mango
something
다음을 시도했지만 위의 두 줄만 제거되었고 내가 찾던 줄은 제거되지 않았습니다.
tac foo.txt |sed '/juice/I,+2 d' |tac
mango
something
위의 스크립트를 적용하면 작업이 가능하다고 생각하지만 확실하지 않습니다.
참고: 일치 항목은 반복되지 않으며 정확히 일치할 필요는 없습니다. 즉, 일치 항목은 긴 줄에서도 찾을 수 있습니다. 일치 항목은 대소문자를 구분해야 합니다.
답변1
가능 하다면 ed
스트림이 아닌 파일을 편집해야 하며 다음 중 하나만 편집해야 합니다 juice
.
$ more <<-EOF | ed -s ./tmp.txt
/juice/
-2
c
coconut
.
w
q
EOF
$
해당 줄을 찾아 두 줄로 이동한 다음 c
hange,
w
rite, q
uit를 수행합니다.
의견에서 @d-ben-knoble이 제안한 보다 컴팩트한 변형은 다음과 같습니다.
$ printf '%s\n' '/^juice$/-2s/.*/coconut/' w q | ed -s ./tmp.txt
답변2
귀하의 접근 방식에 따르면,
tac file|sed '/juice/{n;n;s/.*/coconut/}'|tac
/juice/
라인과 일치합니다juice
.n;n;
현재 줄과 다음 줄을 인쇄합니다.s/.*/coconut/
대체하십시오.
분명히 GNU sed가 있으므로 -z
전체 파일을 메모리에 저장하는 juice를 사용하고 위의 두 번째 줄을 직접 편집할 수도 있습니다.
sed -rz 's/[^\n]*(\n[^\n]*\n[^\n]*juice)/coconut\1/' file
[^\n]
"개행이 아님"을 의미하는 대괄호는 역참조에 의해 복사된 그룹을 캡처합니다 ()
.\1
답변3
$ tac file | awk 'c&&!(--c){$0="coconut"} /juice/{c=2} 1' | tac
coconut
apple
juice
mango
something
답변4
다음은 또 다른 awk
접근 방식입니다. 이번에는 이중 전달입니다.
awk 'NR==FNR&&/juice/{m=FNR} NR>FNR&&FNR==m-2{$0="coconut"} (NR>FNR)' file file
- 우리는 파일을 지정합니다두 배두 번 처리되도록 명령줄 인수로 사용합니다.
- 첫 번째 패스(
FNR
파일별 라인 카운터가NR
전역 라인 카운터와 동일함) 에서는juice
검색 패턴이 발생하는 라인을 간단히 식별하고 이를 변수에 저장합니다m
. - 두 번째 패스에서는 줄 번호를
m-2
대체 텍스트로 설정합니다coconut
. - 일반적으로 수정 사항이 포함된 행을 인쇄하지만 두 번째 단계(조건이
NR>FNR
"true"로 평가되는 경우)에서만 인쇄합니다.
GNU가 있는 경우 awk
(일부 다른 awk
구현에서는 이를 지원함) 다음을 사용하여 일치하는 항목이 발견되자마자 첫 번째 단계를 중단하여 프로세스 속도를 높일 수 있습니다 nextfile
.
awk 'NR==FNR&&/juice/{m=FNR;nextfile} NR>FNR&&FNR==m-2{$0="coconut"} (NR>FNR)' file file