패턴과 일치하는 처음 N 줄을 삭제하고 마지막 줄은 유지합니다.

패턴과 일치하는 처음 N 줄을 삭제하고 마지막 줄은 유지합니다.

정규식과 일치하는 첫 번째 N 줄을 삭제하고 마지막 줄은 유지해야 합니다.

28test
32test
something else
6test
something else
something else
4test
entirelysomethingelse

나는 이런 것을 원한다.

something else
something else
something else
4test
entirelysomethingelse

사용해 보니 sed한 줄과 여러 문자열에서만 작동하는 것 같습니다.

정규식을 사용했습니다.^(.*test)$

답변1

마지막 일치 라인만 유지하는 간단한 방법은 입력을 역방향으로 인쇄하고 첫 번째 일치 라인만 선택한 다음 파이프에서 출력을 역방향으로 인쇄하는 것입니다. tac에서 가정GNU 핵심 유틸리티이용 가능:

tac input_file | awk '!/test$/ || !seen++' | tac >output_file

제자리에서 편집(에서 했던 것처럼)논평)은 일반적으로 인수로 제공된 파일을 처리된 출력으로 덮어쓰는 스크립트나 함수에 명령을 래핑하여 얻습니다.

tmpdir=$(mktemp -d)
cp input_file "$tmpdir/file"
tac "$tmpdir/file" | awk '!/test$/ || !seen++' | tac >input_file
rm -r "$tmpdir"

쉘이 해당 pipefail옵션을 지원하는 경우( setopt PIPE_FAILbusybox ash, yash를 사용하여 bash, ksh93, mksh, zsh를 성공적으로 테스트할 수 있음) 및 : 오류(파이프라인 어디에서나 발생하는 오류 포함)를 set -e사용하면 이를 더 안전하게 만들 수 있습니다. set -o pipefail중지되기 전에 삭제됩니다.

이를 지원하는 플랫폼에서는 문제가 발생하더라도 데이터 손실에 대해 신경 쓰지 않는다고 가정하면 다음을 사용할 수도 있습니다.

{ rm file; tac | awk '!/test$/ || !seen++' | tac >file; } <file

이렇게 하면 inode가 변경됩니다 file(많은 일반 도구에서 제공하는 내부 편집 옵션과 유사).

반대로 첫 번째 항목을 제거하려면N여기서 가정하면 일치하는 라인N= 2:

awk '!/test$/ || ++seen > 2' input_file >output_file

awk이 경우 GNU는 쉽게 편집할 수 있는 다른 라이브러리(특히 자체 "내부" 라이브러리)를 가져올 수 있습니다 gawk.

awk -i inplace '...' file

이에 대한 자세한 내용은 다음을 참조하세요.이 다른 답변U&L에서.

답변2


위의 "패턴과 일치하는 첫 번째 N 줄 삭제" 옵션의 경우 sed예약된 공간(추가 버퍼)에 카운터를 구성할 수 있습니다.

sed -r '/test$/!b;x;s/$/-/;/-{4}/!{x;d};x' file

/test$/!b- 패턴이 일치하지 않으면 무조건 끝으로 점프합니다.
x- 예약된 공간의 모드와 내용을 전환합니다.
s/$/-/- 각 일치 항목에 대해 카운터 끝에 문자를 추가합니다. 제 경우에는 하이픈입니다.
/-{4}/!{x;d}- 카운터에 포함된 문자가 4자 미만인 경우 패턴 공간에서 줄을 삭제합니다.

관련 정보