
다음 텍스트 파일이 있습니다.
banana
apple
juice
mango
something
나는 패턴을 검색 중이며 juice
일치하는 패턴에서 두 번째 줄을 역순으로(즉, 일치하는 패턴 위의 2줄) 찾아서 로 바꾸고 싶습니다 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