Text-Processing
從文件中刪除行到一個模式,除非該模式不存在
我正在嘗試使用類似
sed
或awk
執行以下操作來編寫過濾器:
- 如果輸入中不存在給定模式,則將整個輸入複製到輸出
- 如果輸入中存在模式,則僅將第一次出現之後的行複製到輸出
這恰好適用於“git clean”過濾器,但這可能並不重要。重要的方面是這需要作為過濾器來實現,因為輸入是在標準輸入上提供的。
我知道如何使用
sed
刪除線到一個模式,例如。但是如果在任何地方都不匹配,1,/pattern/d
則會刪除整個輸入。/pattern/
我可以想像編寫一個完整的 shell 腳本來創建一個臨時文件,執行 a
grep -q
或其他操作,然後決定如何處理輸入。如果可能的話,我寧願這樣做而不是亂七八糟地創建一個臨時文件。這需要高效,因為 git 可能會經常呼叫它。
如果您的文件不是太大而無法放入記憶體,則可以使用 perl 來 slurp 文件:
perl -0777pe 's/.*?PAT[^\n]*\n?//s' file
只需更改
PAT
為您所追求的任何模式。例如,給定這兩個輸入文件和模式5
:$ cat file 1 2 3 4 5 11 12 13 14 15 $ cat file1 foo bar $ perl -0777pe 's/.*?5[^\n]*\n?//s' file 11 12 13 14 15 $ perl -0777pe 's/.*?10[^\n]*\n?//s' file1 foo bar
解釋
-pe
:逐行讀取輸入文件,將給出的腳本-e
應用於每一行並列印。-0777
: 將整個文件吞入記憶體。s/.*?PAT[^\n]*\n?//s
:刪除所有內容,直到第一次出現PAT
並且直到行尾。對於較大的文件,我看不出有任何方法可以避免兩次讀取文件。就像是:
awk -vpat=5 '{ if(NR==FNR){ if($0~pat && !a){a++; next} if(a){print} } else{ if(!a){print} else{exit} } }' file1 file1
解釋
awk -vpat=5
: 執行awk
並將變數設置pat
為5
.if(NR==FNR){}
: 如果這是第一個文件。if($0~pat && !a){a++; next}
: 如果這一行與 的值匹配pat
並且a
未定義,則加a
一併跳到下一行。if(a){print}
: 如果a
已定義(如果此文件與模式匹配),則列印該行。else{ }
:如果這不是第一個文件(所以它是第二遍)。if(!a){print}
如果a
沒有定義,我們想要整個文件,所以列印每一行。else{exit}
: 如果a
已定義,我們已經在第一遍列印,因此無需重新處理文件。