他のパターンの前に最後に表示されるパターンを取得します。

他のパターンの前に最後に表示されるパターンを取得します。

次のファイルから:

...
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一部の行が一致する前に少なくとも1つの行が一致する場合にのみ終了するため、次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

関連情報