读取行替代品时的grep

时间:2013-04-26 04:07:43

标签: linux bash shell

我有一个日志文件.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。 这些行可以包含一个或两个或三个字符串。

我第一次尝试使用,同时阅读LINE do 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

这可以按预期工作,但它根本没有优化,而且速度很慢。

感谢您的帮助!

4 个答案:

答案 0 :(得分:1)

有很多方法可以实现这一目标。既然你似乎更喜欢shell,你应该看一下awk,它基本上就是为了做到这一点。

Perl也适用于此类任务。一个简单的脚本,带有几个正则表达式以匹配您的搜索字词,然后打印。

答案 1 :(得分:1)

try grep -oE "string[0-9]" file.log >> results.csv -o标志仅将匹配的部分作为输出

答案 2 :(得分:0)

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

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

答案 3 :(得分:0)

使用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完成。