取得一個模式在另一個模式之前最後一次出現的情況

取得一個模式在另一個模式之前最後一次出現的情況

在這樣的文件中:

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

相關內容