grep包含两个或多个单词,一行一行,包含许多文件

时间:2019-02-24 06:48:46

标签: linux grep

每个人。我有

file 1.log: text1 value11 text text text text2 value12 text

file 2.log: text1 value21 text text text text2 value22 text

我想要:

value11;value12 value21;value22

目前,我将grep值放在分开的文件中,然后再粘贴到另一个文件中,但是我认为这不是一个非常好的解决方案,因为我需要多次读取所有文件,因此我尝试使用grep提取所有数据一只猫| grep行,但不是我预期的结果。

我使用: cat *.log | grep -oP "(?<=text1 ).*?(?= )|(?<=text2 ).*?(?= )" | tr '\n' '; '

cat *.log | grep -oP "(?<=text1 ).*?(?= )|(?<=text2 ).*?(?= )" | xargs

但在每种情况下我都会得到:

value11;value12;value21;value22

value11 value12 value21 value22

非常感谢您。

3 个答案:

答案 0 :(得分:0)

尝试:

$ awk -v RS='[[:space:]]+' '$0=="text1" || $0=="text2"{getline; printf "%s%s",sep,$0; sep=";"} ENDFILE{if(sep)print""; sep=""}' *.log
value11;value12
value21;value22

对于那些喜欢将命令分布在多行上的人:

awk -v RS='[[:space:]]+' '
    $0=="text1" || $0=="text2" {
        getline
        printf "%s%s",sep,$0
        sep=";"
     }
     ENDFILE {
        if(sep)print""
        sep=""
     }' *.log

工作原理

  • -v RS='[[:space:]]+'

    这告诉awk将空白序列(换行符,空格,制表符等)视为记录分隔符。

  • $0=="text1" || $0=="text2"{getline; printf "%s%s",sep,$0; sep=";"}

    这告诉awk查找与text1 or text2`匹配的文件记录。对于那些记录和那些记录,仅执行大括号中的命令。这些命令是:

    • getline告诉awk读取下一条记录。

    • printf "%s%s",sep,$0告诉awk打印变量sep,后跟记录中的单词。

    • 在打印第一个匹配项之后,将执行命令sep=";",该命令告诉awk将sep的值设置为分号。

      启动每个文件时,sep为空。这意味着将打印任何文件中的第一个匹配项,并且前面没有分隔符。同一文件中的所有后续匹配项都将带有;来分隔它们。

  • ENDFILE{if(sep)print""; sep=""}

    到达每个文件的末尾后,如果sep不为空,则打印换行符,然后将sep设置为空字符串。

替代:如果第一个单词以数字结尾,则打印第二个单词

在对问题的另一种解释(提示:David C. Rankin)中,我们想在第一个单词以数字结尾的任何行上打印第二个单词。在这种情况下,请尝试:

$ awk '$1~/[0-9]$/{printf "%s%s",sep,$2; sep=";"} ENDFILE{if(sep)print""; sep=""}' *.log
value11;value12
value21;value22

在上面,$1~/[0-9]$/选择第一个单词以数字结尾的行,printf "%s%s",sep,$2在该行上打印第二个字段。

讨论

原始命令是:

$ cat *.log | grep -oP "(?<=text1 ).*?(?= )|(?<=text2 ).*?(?= )" | tr '\n' '; '
value11;value12;value21;value22;

请注意,在使用大多数UNIX命令时,几乎不需要cat。在这种情况下,例如,grep接受文件列表。因此,我们无需额外的cat流程就可以轻松完成操作,并获得相同的输出:

$ grep -hoP "(?<=text1 ).*?(?= )|(?<=text2 ).*?(?= )" *.log | tr '\n' '; '
value11;value12;value21;value22;

答案 1 :(得分:0)

我同意@John1024的看法,您如何解决此问题实际上取决于您要寻找的实际文本。例如,如果您的关注点从text{1,2,...}开始,然后在第二个字段中想要的内容可以是任何内容,那么他​​的方法是最佳的。但是,如果第一个字段中的值各不相同,而您真正感兴趣的是第二个字段中有valueXX的记录,那么寻找第二个字段的方法可能就是您想要的。 / p>

以第二个字段为例,如果您感兴趣的文本的格式为valueXX(其中XX是字段末尾的两位或多个数字),则只能处理那些与您的第二个字段匹配的记录,然后使用简单的条件测试,来类似于FNR == 1是否控制';'分隔符输出和ENDFILE是否控制新行:

awk '$2 ~ /^value[0-9][0-9][0-9]*$/ {
    printf "%s%s", (FNR == 1) ? "" : ";", $2
}
ENDFILE {
    print ""
}' file1.log file2.log

使用/输出示例

$ awk '$2 ~ /^value[0-9][0-9][0-9]*$/ {
    printf "%s%s", (FNR == 1) ? "" : ";", $2
}
ENDFILE {
    print ""
}' file1.log file2.log
value11;value12
value21;value22

仔细研究一下并考虑您的实际输入文件,然后这两种方法中的任何一种都可以使您到达那里。

答案 2 :(得分:0)

如果我对您的理解正确,则需要values,但要搜索text[12],即。在匹配搜索字词之后而不是匹配搜索字词后得到字词:

$ awk -v s="^text[12]$" '                   # set the search regex *
FNR==1 {                                    # in the beginning of each file
    b=b (b==""?"":"\n")                     # terminate current buffer with a newline
}
{
    for(i=1;i<NF;i++)                       # iterate all but last word
        if($i~s)                            # if current word matches search pattern
            b=b (b~/^$|\n$/?"":";") $(i+1)  # add following word to buffer
}
END {                                       # after searching all files
    print b                                 # output buffer
}' *.log

输出:

value11;value12
value21;value22

{* regex也可以是^(text1|text2)$