일치하는 패턴의 n번째 줄을 바꿉니다.

일치하는 패턴의 n번째 줄을 바꿉니다.

다음 텍스트 파일이 있습니다.

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
$

해당 줄을 찾아 두 줄로 이동한 다음 change, write,  quit를 수행합니다.


의견에서 @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

관련 정보