일치하는 항목이 포함된 첫 번째 줄 앞의 모든 줄을 삭제하시겠습니까?

일치하는 항목이 포함된 첫 번째 줄 앞의 모든 줄을 삭제하시겠습니까?

정규식 문자열을 사용하여 일치 항목이 포함된 첫 번째 줄 앞의 모든 줄을 어떻게 삭제할 수 있습니까? 예를 들어 이것을 어떻게 변경할 수 있습니까?

lost
load
linux
loan
linux

다음을 입력하세요:

linux
loan
linux

나는 시도했다:

echo "lost
load
linux
loan
linux" | sed -e 's/.*^li.*$//g'

그러나 아무것도 변경하지 않고 다음을 반환합니다.

lost
load
linux
loan
linux

일치하는 항목이 없을 때 아무 것도 출력하지 않도록 작동하기를 원합니다.

답변1

단방향 POSIXly:

$ echo "lost
load
linux
loan
linux" | sed -e/linux/\{ -e:1 -en\;b1 -e\} -ed

또는 더 짧게:

sed -n '/linux/,$p'

더 짧게:

sed '/linux/,$!d'

짧은 버전보다 긴 버전을 선호하는 이유를 궁금해하는 독자를 위해 긴 버전은 파일의 나머지 부분에 대한 I/O만 수행하는 반면, 범위를 사용하면 두 번째 주소가 regex인 경우 성능이 저하되고 정규식은 다음을 시도합니다. 필요한 것 이상으로 일치시킵니다.

고려하다:

$ time seq 1000000 | sed -ne '/^1$/{' -e:1 -en\;b1 -e\}
=====
JOB sed -e '/^1$/,$d'
87%    cpu
0.11s real
0.10s user
0.00s sys

그리고:

$ time seq 1000000 | sed -e '/^1$/,/1000000/d'
=====
JOB sed -e '/^1$/,/1000000/d'
96%    cpu
0.24s real
0.23s user
0.00s sys

두 버전의 차이점을 확인할 수 있습니다. 복잡한 정규식의 경우 이는 큰 차이를 만듭니다.

답변2

이는 명확하게 수행하기 쉽습니다 awk.

echo "lost
load
linux
loan
linux" | awk '
    /^li/ { found = 1 }
    found { print }'

이는 found임의로 선택한 자체 설명 이름을 가진 변수입니다. 프로그램이 정규식과 일치하는 입력 줄을 발견하면 설정됩니다. (변수의 초기 기본값은 0 또는 FALSE와 기능적으로 동일한 null입니다.) 따라서 입력 줄은 ^li패턴 일치 이전이 아닌 이후에 인쇄됩니다. linux패턴을 찾고 플래그를 설정하는 명령문 뒤에 조건부 인쇄 문이 오기 때문에 입력의 세 번째 줄(첫 번째 줄)을 인쇄합니다 . 네 번째 줄(줄)부터 인쇄를 시작하려면뒤쪽에첫 번째 linux줄) 두 명령문의 순서를 반대로 바꾸면 됩니다.

정규식과 일치하는 입력 줄이 없으면 플래그가 설정되지 않으며 아무 것도 인쇄되지 않습니다.

앞서 말했듯이 플래그 변수의 이름은 임의적입니다. f필요한 경우 더 짧은 이름(예: )을 사용할 수 있습니다. 그리고 { print }기본 동작이므로 생략해도 됩니다. 따라서 명확성이 중요하지 않다면 위의 내용을 다음과 같이 단축할 수 있습니다.

echo "lost
load
linux
loan
linux" | awk '/^li/{f=1}f'

답변3

다른 두 가지 awk 솔루션:

둘 다 found첫 번째 정규식 일치를 볼 때 플래그를 설정하고 해당 플래그가 설정되면 인쇄합니다.

echo "lost
load
linux
loan
linux" | awk 'BEGIN {found = 0} {if (found || $0 ~ /linux/) {found = 1; print}}'

이것은 약간 길지만 found플래그를 다시 설정하지는 않습니다.

echo "lost
load
linux
loan
linux" | awk 'BEGIN {found = 0} {if (found) {print} else if ($0 ~ /linux/) {found = 1; print}}'

답변4

당신은 그것을 사용할 수 있습니다전임자배치 모드에서 파일을 직접 편집합니다. (실제로 파일을 변경하기 전에 출력 파일이 무엇인지 확인하고 싶다면 . 로 바꾸세요 x. %p)

printf '%s\n' 'a' 'linux' '.' '1,/linux/-1d' '$d' 'x' | ex -s file
  1. a, linux, write는 .끝에 한 줄을 추가합니다.linux
  2. 1,/linux/-1d간격 [파일의 첫 번째 줄, 첫 번째 앞의 첫 번째 줄 ] linux에서 줄을 삭제합니다.
  3. $d1단계에서 수동으로 삽입한 행을 삭제합니다.
  4. x변경사항을 작성하고 종료합니다.

보다 직접적인 접근 방식(참조:편집 기록의 첫 번째 버전) 일치하는 항목이 없으면 파일은 변경되지 않은 상태로 유지됩니다. 이렇게 하면 필요에 따라 파일이 지워집니다(따라서 이상한 1단계).

$ cat file1
lost
load
linux
loan
linux
$ printf '%s\n' a linux . 1,/linux/-1d '$d' x | ex -s file1
$ cat file1
linux
loan
linux
$ cat file2
lost
load
loan
$ printf '%s\n' a linux . 1,/linux/-1d '$d' x | ex -s file2
$ cat file2  #file2 is empty

관련 정보