【问题标题】:Grep text between patterns using bash [closed]使用 bash 在模式之间查找文本 [关闭]
【发布时间】:2016-05-18 17:04:32
【问题描述】:

我需要对 txt 文件中的数据进行排序。样本数据如下:

======
Jhon 
Doe 
score -
------  
======
Ann 
Smith 
score + 
------
======
Will 
Marrow 
score - 
------

我只需要提取定义了score + 的部分。所以结果应该是

======
Ann 
Smith 
score + 
------

【问题讨论】:

  • 也许写一个 perl 脚本更好
  • 是的,如果它解决了这个任务
  • sed, grep 只处理行。你想要多线匹配

标签: bash awk sed grep


【解决方案1】:

试试这个oneliner:

awk -v RS="==*" -F'\n' '{p=0;for(i=1;i<=NF;i++)if($i~/score \+/)p=1}p' file

使用给定的数据,它会输出:

Ann 
Smith 
score + 
------

思路是,将所有除以====...的行作为一个多行记录,检查记录是否包含搜索模式,打印出来。

【讨论】:

  • 太棒了,按预期工作!如果定义了更多模式,您能否还展示如何提取数据。例如。不仅得分+,而且还有一个,例如:年龄 - gist.github.com/Demontager/947590bdcf28f55b1018 所以两个模式应该只在 ==== 和 -----
  • @Demontager 如果要检查A和B,只需将逻辑写入if(..)
【解决方案2】:

给定:

$ echo "$txt"
======
Jhon 
Doe 
score -
------  
======
Ann 
Smith 
score + 
------
======
Will 
Marrow 
score - 
------

您可以在 awk 中创建切换类型匹配以仅打印您想要的部分:

$ echo "$txt" | awk '/^=+/{f=1;s=$0;next} /^score \+/{f=2} f {s=s"\n"$0} /^-+$/ {if(f==2) {print s} f=0}'
======
Ann 
Smith 
score + 
------

【讨论】:

    【解决方案3】:

    我会试试这个:

    $ grep -B3 -A1 "score +" myfile
    

    这意味着... grep 三行B之前和一行A“score +”之后。

    【讨论】:

    • 是的,工作非常小。但是,如果每个部分中的行数相等,则按预期提取数据。对于我的例子,它很合适。
    【解决方案4】:

    Sed 可以这样做:

    sed -n '/^======/{:a;N;/\n------/!ba;/score +/p}' infile 
    ======
    Ann 
    Smith 
    score + 
    ------
    

    -n 阻止打印,并且

    /^======/ {       # If the pattern space starts with "======"
        :a            # Label to branch to
        N             # Append next line to pattern space
        /\n------/!ba # If we don't match "------", branch to :a
        /score +/p    # If we match "score +", print the pattern space
    }
    

    使用/\n------$/ 可以更恰当地锚定事物,但行尾有空格,我不确定这些是真实的还是复制粘贴的伪像——但这适用于示例数据。

    【讨论】:

    • 测试过,也可以工作!更优雅的方式,我理解它的逻辑。如果我想要 === 和 --- 之间的两个匹配模式 --- 示例 gist.github.com/Demontager/947590bdcf28f55b1018(添加年龄 -)?
    • @Demontager age - 总是在score + 之后吗?
    • ===和----之间的任何地方
    • 您必须将score 行替换为/score +/{/age -/p}
    • 我做错了 $ sed -n '/^======/{:a;N;/-------/!ba;/score +/{/age -/p}' test1.txt sed: -e expression #1, char 0: unmatched `{' 能否请您显示完整行。
    【解决方案5】:

    使用 GNU awk 进行多字符 RS:

    $ awk -v RS='=+\n' '/score \+/' file
    Ann 
    Smith 
    score + 
    ------
    

    【讨论】:

      【解决方案6】:

      使用 Grep 上下文标志

      假设您有一个真正的固定格式文件,您可以使用 fgrep(或带有快速 --fixed-strings 标志的 GNU 或 BSD grep)以及--before-context--after-context 标志。例如:

      $ fgrep -A1 -B3 'score +' /tmp/foo 
      ======
      Ann 
      Smith 
      score + 
      ------
      

      标志将找到您的匹配项,并包括每次匹配之前的三行和之后的一行。这为您提供了您所追求的输出,但比 sed 或 awk 脚本的复杂性要低得多。 YMMV。

      【讨论】:

        猜你喜欢
        • 2012-03-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-12-26
        • 2014-10-12
        • 2015-08-03
        • 2011-08-05
        • 1970-01-01
        相关资源
        最近更新 更多