我想逐行读取文本文件以搜索模式;当找到一行中的第一个匹配项时,将其打印到文件中,然后移动到下一行中搜索模式。
由于我在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 任何shell实用程序(如grep、awk、sed、perl )都可以。
发布于 2017-01-02 21:37:43
下面是一个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。
发布于 2017-01-02 21:29:55
要想直接使用grep实现这一点,您必须使用某种可变长度的负后视,以确保您正在查看行中的第一次约会。显然,Perl兼容的正则表达式就能做到与“回溯控制动词”兼容,但我不确定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输入文件的快速性能比较:
https://stackoverflow.com/questions/41430802
复制相似问题