다른 패턴 이전에 마지막으로 나타나는 패턴을 가져옵니다.

다른 패턴 이전에 마지막으로 나타나는 패턴을 가져옵니다.

다음과 같은 파일에서:

...
Pattern2:TheWrongBar
foo 
Pattern2:TheRightBar
foo 
First Pattern
foo
...

Pattern2이 조건 이전에 발생한 이 조건의 마지막 발생을 찾아야 합니다.First PatternPattern2:TheRightBar

내 첫 번째 생각은 이전의 나머지 파일을 모두 가져오는 것이었습니다 First pattern.

sed -e '/First Pattern/,$d' myfile | tac | grep -m1 "Pattern I need to get"

이 코드를 최적화할 방법이 없나요?

답변1

그리고 awk:

awk '/Pattern2/ {line=$0; next}; /First Pattern/ {print line; exit}' file.txt
  • /Pattern2/ {line=$0; next}: 패턴이 Pattern2일치하면 해당 줄을 변수에 저장 line하고 다음 줄로 이동합니다.

  • /First Pattern/ {print line; exit}: 발견되면 First Pattern변수를 인쇄 line하고 종료합니다.

예:

% cat file.txt                                                                 
...
Pattern2:TheWrongBar
foo 
Pattern2:TheRightBar
foo 
First Pattern
foo
...

% awk '/Pattern2/ {line=$0; next}; /First Pattern/ {print line; exit}' file.txt
Pattern2:TheRightBar

답변2

넌 달릴 수 있어

sed '/PATTERN2/h;/PATTERN1/!d;x;/PATTERN2/!d;q' infile

작동 방식:

sed '/PATTERN2/h         # if line matches PATTERN2 save it to hold buffer 
/PATTERN1/!d             # if it doesn't match PATTERN1 delete it
x                        # exchange buffers
/PATTERN2/!d             # if current pattern space doesn't match delete it
q' infile                # quit (auto-printing the current pattern space)

PATTERN2일부 행이 일치하기 전에 적어도 하나의 행이 일치하는 경우에만 종료되므로 PATTERN1다음과 같이 입력하십시오.

1
2
PATTERN1
PATTERN2--1st
3
PATTERN2--2nd
PATTERN1
...

그것은 인쇄됩니다

PATTERN2--2nd

첫 번째 게임에서 종료하고 싶다면 PATTERN1다음을 실행하세요.

sed -n '/PATTERN2/h;/PATTERN1/!d;x;/PATTERN2/p;q' infile

위의 입력은 아무것도 인쇄하지 않습니다(정확히 솔루션이 수행하는 작업입니다).

답변3

"첫 번째 패턴"의 줄 번호를 찾은 다음 head를 사용하여 그 위에 있는 줄을 표시하고 tac을 통해 파이프한 다음 grep합니다.

head --lines=+"$(grep -nm1 "First Pattern" file | cut -d\: -f1)" file | tac | grep -m1 "Pattern2" 

예를 들어.

head --lines=+6 file | tac | grep -m1 "Pattern2" 

이는 grep과 함께 -m 1000000을 사용하는 것보다 더 안정적입니다. OP에는 속도가 중요했기 때문에 실행 시간을 확인했는데 (내 시스템의) 현재 다른 모든 답변보다 빠른 것 같았습니다.

wc -l file
25910209 file

time awk '/Pattern2/ {line=$0; next}; /First Pattern/ {print line; exit}' file
Pattern2:TheRightBar

real  0m2.881s
user  0m2.844s
sys 0m0.036s

time sed '/Pattern2/h;/First Pattern/!d;x;/Pattern2/!d;q' file
Pattern2:TheRightBar

real  0m5.218s
user  0m5.192s
sys 0m0.024s

time (grep -m1 "First Pattern" file -B 10000000 | tac | grep -m1 "Pattern2")

real  0m0.624s
user  0m0.552s
sys 0m0.124s

time (head --lines=+"$(grep -nm1 "First Pattern" file | cut -d\: -f1)" file | tac | grep -m1 "Pattern2")
Pattern2:TheRightBar

real  0m0.586s
user  0m0.528s
sys 0m0.160s

답변4

가장 효과적인 방법나로서는예전에는 :

grep -m1 "First Pattern" my_file -B 10000000 | tac | grep -m1 "Pattern2"

분명히 이 -B옵션은 일부 예에서는 작동하지 않지만 grep이 솔루션에 사용한 것보다 훨씬 빠릅니다. 옵션의 가치가 높아지면 검색 효율이 떨어지게 됩니다.awksed-B

관련 정보