다른 패턴 이전에 마지막으로 나타나는 패턴 가져오기

다른 패턴 이전에 마지막으로 나타나는 패턴 가져오기

다음과 같은 파일에서 :

...
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

관련 정보