Text-Processing

從文件中刪除行到一個模式,除非該模式不存在

  • October 4, 2016

我正在嘗試使用類似sedawk執行以下操作來編寫過濾器:

  • 如果輸入中不存在給定模式,則將整個輸入複製到輸出
  • 如果輸入中存在模式,則僅將第一次出現之後的行複製到輸出

這恰好適用於“git clean”過濾器,但這可能並不重要。重要的方面是這需要作為過濾器來實現,因為輸入是在標準輸入上提供的。

我知道如何使用sed刪除線到一個模式,例如。但是如果在任何地方都不匹配,1,/pattern/d則會刪除整個輸入。/pattern/

我可以想像編寫一個完整的 shell 腳本來創建一個臨時文件,執行 agrep -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並將變數設置pat5.
  • if(NR==FNR){}: 如果這是第一個文件。
  • if($0~pat && !a){a++; next}: 如果這一行與 的值匹配pat並且a未定義,則加a一併跳到下一行。
  • if(a){print}: 如果a已定義(如果此文件與模式匹配),則列印該行。
  • else{ }:如果這不是第一個文件(所以它是第二遍)。
  • if(!a){print}如果a沒有定義,我們想要整個文件,所以列印每一行。
  • else{exit}: 如果a已定義,我們已經在第一遍列印,因此無需重新處理文件。

引用自:https://unix.stackexchange.com/questions/217988