grep而读取行的替代品

我有一个日志file.log:

toto string1 tata string2 tito string3 tata tati string3 titi string1 tato string2 tati toto ..... tutu string1 tita string2 tita string3 

我需要从文件的每一行中提取string1,string2和string3。 行可以包含一个或两个或三个string。

我第一次尝试使用,而阅读LINE做grep:

 while read line; do z_string1=`echo $line | egrep 'string1' | cut -f2 xxx | cut -f1 xxxx` z_string2=`echo $line | egrep 'string2' | cut -f2 xxx | cut -f1 xxxx` z_string3=`echo $line | egrep 'string3' | cut -f2 xxx | cut -f1 xxxx` echo "$z_string1,$z_string2,$z_string3" >> results.csv done < file.log 

这可以按预期的方式工作,但是并没有完全优化,而且速度很慢。

感谢您的帮助!

有很多方法来实现这一点。 因为你似乎更喜欢shell,所以你应该看看awk ,这基本上是为了做到这一点。

Perl也专门用于这类任务。 一个简单的脚本,有几个正则表达式来匹配您的搜索条件,然后是一个打印。

  • Perl介绍 – 正则表达式

尝试grep -oE "string[0-9]" file.log >> results.csv -o标志只给出匹配的部分作为输出

从我可以看到你的字符串模式正在改变列:

 toto string1 tata string2 tito **string3** tata tati string3 titi string1 tato string2 tati toto ..... tutu string1 tita string2 tita string3 

第二行是第三列,其余的是第二列,所以没有依靠列号输出的点可以在这里看到:

 awk -v pattern="string" '{cols=NF; if ( (cols == 6 ) && ($2 ~ pattern)) { print $2 " " $4 " " $6 } }' test.txt string1 string2 string3 string1 string2 toto string1 string2 string3 

所以..

你可以使用这个或这部分的解决方案

  awk -v p1="string1" -v p2="string2" -v p3="string3" 'BEGIN { c1=0; c2=0; c3=0; } {if (( $0 ~ p1) || ( $0 ~ p2) || ($0 ~ p3 )) { for (i=1;i<=NF;i++) { if ( $i ~ p1) { print $i; c1++; } else if ( $i ~ p2) { print $i; c2++; } else if ( $i ~ p3) { print $i; c3++; } } } } END{ print p1"_count:" c1 " "p2"_count:" c2" "p3"_count:"c3} ' test.txt 

这产生:

 string1 string2 string3 string3 string1 string2 string1 string2 string3 string1_count:3 string2_count:3 string3_count:3 

使用bash正则表达式匹配捕获字符串(如果存在),然后打印它们。 我从你的例子中假设你只是想打印一个空字符串,如果没有找到匹配,所以我保留这种行为。

 while read line; do [[ $line =~ (string1) ]]; printf "%s," "$BASH_REMATCH" [[ $line =~ (string2) ]]; printf "%s," "$BASH_REMATCH" [[ $line =~ (string3) ]]; printf "%s\n" "$BASH_REMATCH" done 

这可能不像perlawk解决方案那样快,但应该是对原始的改进,因为不需要创建额外的进程; 一切都在bash完成。