[英]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輸入文件的快速性能比較:
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.