簡體   English   中英

逐行讀取文件,並在沒有匹配項時打印每行中的第一個匹配項或“ no_data”

[英]Read file line by line and print the first match in each line or “no_data” when nothing matches

我想逐行閱讀文本文件以搜索模式; 找到一行中的第一個匹配項后,將其打印到文件中並移動以在下一行中搜索模式。

由於我在Shell方面的技能有限,我嘗試了以下方法: 不幸的是,當沒有第一個模式時,它永遠不會將no_data打印到文件d.txt

while read u ; do
    echo "$u" | grep -o '[0-9]\{2\}/[0-9]\{2\}/[0-9]\{4\}  [0-9]\{2\}:[0-9]\{2\}' |head -1 || echo "no_data" 
done < tmc.txt > d.txt

注意:我要匹配的模式是日期和時間戳,格式為mm/dd/yyyy hh:mm

例如, $u可以是這樣的字符串,甚至可以包含各種垃圾的更大字符串:

disk0/bcdackup_20160908_115716/d/.ER/ERORR_log_msnf_20160906_113039:10641:  Test Status:         Failed ;Test PL (some test) was started in execution mode.  09/06/2016  14:43:28.4954  Machine:msnf  (Rl888751, , ?.?, 1637) USER EVENT: TM-1102 DEFAULT  -- SYSTEM ERROR: TX-0003 INIT  Function Protocol Violation. Verification by TXXAxREQxConfig_destroy_config failed: 'engine_ptr != NULL' not TRUE  -- SYSTEM EVENT: ER-0FFF DEFAULT (linked to IH-154B) DEACTIVATE: IH-154b DEACTIVATE: IH-154b  -- SYSTEM EVENT: ER-0FFF DEFAULT (linked to IH-154C) DEACTIVATE: IH-154c DEACTIVATE: IH-154c  -- SYSTEM ERROR: WP-2631 CHANGEPARAMS  Error during processing of Finite State Machine Error starting perform_smooth_landing : event perform_smooth_landing not allowed in state {original_mc, actuator_system_enabled, service_off, not_homed} of state-machine WPLS.V1.2  -- SYSTEM ERROR: WP-2630 CHANGEPARAMS  Error during processing of F   

我可以使用grep,awk,sed,perl等任何shell實用程序。

這是一個Perl解決方案:

perl -nle 'print m{(\d{2}/\d{2}/\d{4} \d{2}:\d{2})} ? $1 : "no_data"' < tmc.txt > d.txt

-n循環輸入中的行。

-l自動刪除輸入中的換行符,並將其添加到輸出中。

對於每一行,我們都會與捕獲組進行簡單的正則表達式匹配。 如果成功,我們將打印匹配的字符串,否則將no_data

要直接使用grep執行此操作,您必須使用某種可變長度的負向后查找,以確保您正在查看該行中的第一個日期。 顯然,與Perl兼容的正則表達式可以使用“回溯控制動詞” 來做到這一點 ,但a)我不確定grep -P支持那些正則表達式,以及b)您還想替換不匹配的行,grep可以做到這一點'還是做。

作為在每一行上調用grep的替代方法,您可以使用sed:

sed -r '
    /([0-9]{2}\/){2}[0-9]{4} +[0-9]{2}:[0-9]{2}/! { # On non-matching lines...
        s/.*/no_data/                               # Replace line with "no_data"
        b                                           # Skip to next line
    }
    s/(([0-9]{2}\/){2}[0-9]{4} +[^ ]*).*/\1/ # Remove everything after first date
    s/.*(([0-9]{2}\/){2}[0-9]{4})/\1/        # Remove everything before first date
' infile

對於使用示例行的infile版本,其三次(第一次刪除兩個日期,然后刪除第一個日期,然后刪除兩個日期),輸出為

$ sed -r '/([0-9]{2}\/){2}[0-9]{4} +[0-9]{2}:[0-9]{2}/!{s/.*/no_data/;b};s/(([0-9]{2}\/){2}[0-9]{4} +[^ ]*).*/\1/;s/.*(([0-9]{2}\/){2}[0-9]{4})/\1/' infile
09/06/2016  14:43:28.4954
08/06/2016  18:53:28.4757
no_data

如預期的那樣。

sed命令首先檢查該行是否包含日期;然后檢查該行是否包含日期。 如果不是,則用no_data替換整行,並跳過其余命令。 他們實際上不會做任何事情,但這應該使執行速度更快。

如果該行中確實包含日期,則會執行兩次替換:第一個替換將刪除第一個日期之后的所有內容,第二個替換將其之前的所有內容刪除。 必須分兩步進行,否則貪婪的匹配將導致打印該行的最后日期。


40 MB輸入文件的快速性能比較:

  • Bash循環在每行上調用grep:〜24秒
  • Sed:〜4秒
  • Perl:<0.1秒

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM