【问题标题】:How can I get words between the first two instance of text/pattern?如何在文本/模式的前两个实例之间获取单词?
【发布时间】:2019-05-15 10:47:15
【问题描述】:

输入:

===================================
v2.0.0

Added feature 3
Added feature 4
===================================
v1.0.0

Added feature 1
Added feature 2
===================================

我想要的输出:

v2.0.0

Added feature 3
Added feature 4

我尝试了this,但它得到了 first 等于 (=) 和 LAST 等于 (=) 而我想要的是 FIRST 两个等于 (=)

【问题讨论】:

    标签: linux bash awk sed grep


    【解决方案1】:

    这是 awk 中的一个:

    $ awk '/^=+$/{f=!f;if(f==1)next;else if(f==0)exit}f' file
    v2.0.0
    
    Added feature 3
    Added feature 4
    

    印刷精美:

    $ awk '/^=+$/ {     # at ===...
        f=!f            # flag state is flipped
        if(f==1)        # if its one (first ===...)
            next        # next record
        else if(f==0)   # if zero (second ===...)
            exit        # nothing more to do yeah
    }
    f' file             # print
    

    【讨论】:

      【解决方案2】:

      您也可以尝试一下吗?

      awk '/^=/{count++;next} count>=2{exit} {print}'  Input_file
      

      【讨论】:

      • count>=2 会更好,以防第二个 ==== 紧邻第二个。
      • @JamesBrown,现在肯定做到了,谢谢你让我知道。
      【解决方案3】:

      使用 GNU awk 进行多字符 RS:

      $ awk -v RS='(^|\n)=+\n' 'NR==2' file
      v2.0.0
      
      Added feature 3
      Added feature 4
      

      对于任何其他 awk,等价物会更长:

      $ awk '
          /^=+$/ { prt(); next }
          { rec=rec $0 ORS }
          END { prt() }
          function prt() { if (++nr==2) printf "%s", rec; rec="" }
      ' file
      v2.0.0
      
      Added feature 3
      Added feature 4
      

      请注意,以上内容可以打印任意数量的记录,而不仅仅是第二条,只需将 2 更改为您想要打印的任何记录号,您可以简单地添加/更改条件,例如仅打印包含一些记录的记录基于记录号的字符串代替或补充,例如如果包含foo,则打印第 17 条记录:

      awk -v RS='(^|\n)=+\n' 'NR==17 && /foo/' file
      

      说明:您的记录由 === 行分隔,因此将记录分隔符 RS 设置为与该描述匹配的正则表达式,然后在记录数 (NR) 达到所需数量时打印记录,即 2(因为在第一行 === 之前有一条空记录)。

      【讨论】:

      • 您的第一个解决方案与 sed 解决方案一样聪明、简洁且令人困惑! ;-)
      • 我们必须同意不同意我怀疑的观点。您的记录由=== 行分隔,因此将RS 设置为与该描述匹配的正则表达式,然后只需打印您想要的记录号 - 对我来说似乎非常清晰、简单和明显。与 sed 解决方案相比,它还具有优势,即不需要完全重写即可打印第 17 条记录而不是第 2 条记录,或者测试记录的其他内容或执行其他任何操作。
      • 不,不,我确实明白了。花了我几分钟。我想,清楚是主观的。但我相当肯定,像你一样不了解 AWK 的人不会知道它是如何工作的。
      • 同意。当您提供工具构造以使作业 X(例如在 awks 案例中操作文本)更容易时,人们必须阅读手册页以了解这些构造的含义。如果您不知道 awk 具有隐式 while-read 循环和隐式 if-condition-action 块,默认操作为 print,并且它将所有输入视为由 RS 分隔的记录,并且记录号存储在 NR 中您将没有机会弄清楚该脚本的作用。另一方面,一旦您知道这些以及 4 或 5 个其他基础知识(字段/变量),其他所有文本操作任务都很简单
      • 我不是 awk 菜鸟,但肯定一点也不精通它,而且确实比 awk 更了解 RegEx。我认为在我看来,我混淆了字段分隔符而不是记录分隔符,因为我倾向于使用 -F 而不需要 -v ,而不是 FSRS ,其中需要以 -v 开头。反正就是个大脑袋屁!感谢您的回答,即使这不是我的 OP,我仍然学到了一些东西! :)
      【解决方案4】:

      这是 GNU sed 中的另一个:

      $ sed -n '/^=\+$/,//{//!p;b};q' file
      v2.0.0
      
      Added feature 3
      Added feature 4
      
      • /^=\+$/,///^=\+$/,/^=\+$/ 的简写,它选择包含等号的两行之间的行,并为这些行执行后面花括号之间的命令,
      • //!p/^=\+$/!p 的简写,表示如果传入线路不是仅包含 =s 的线路之一,则打印出来,
      • b 表示循环结束(即通过q),
      • q 用于在打印选定行后退出 sed。

      以下版本将适用于所有符合 POSIX 的 sed,但它看起来更神秘 2 倍:

      sed -n -e '/^=\{1,\}$/,//{//!p;b' -e '}' -e 'q' file
      

      请注意,如果输入中有两个后续的所有= 行,则这些行将不起作用。

      【讨论】:

      • 看起来更加神秘。 ++
      【解决方案5】:

      这可能对你有用(GNU sed):

      sed -n '/^=\+$/{:a;n;//q;p;ba}' file
      

      通过设置选项-n 使用显式打印,这意味着行将仅由pP 命令打印。

      遇到包含所有= 字符的行时,获取下一行,如果其中包含相同的正则表达式,则退出文件。否则打印当前行并重复。

      【讨论】:

        【解决方案6】:

        可以说,一个更干净的 GNU sed 解决方案:

        sed -E '0,/^={35}$/d; //Q'
        

        或者,如果您对其他答案中提出的更简单的正则表达式感到满意:

        sed -E '0,/^=+$/d; //Q'
        

        进一步说明:

        • (扩展,注意-E)正则表达式/^={35}$/ 匹配一行,就像你的一样,由35个等号组成。 (替代正则表达式/^=+$/ 匹配包含一个或多个等号的行。)

        • 命令0,/^={35}$/d 选择从文件开头到模式第一次出现的所有行,并删除。

        • 表达式 // 导致 sed 正则表达式默认为用作地址或 s/// 命令一部分的最后一个正则表达式。

        • Q 命令是 GNU 扩展,它会导致 sed 退出而不打印。

        对此进行测试:

        # test.sh
        
        cat > FILE <<EOF
        other
        text
        ===================================
        v2.0.0
        
        Added feature 3
        Added feature 4
        ===================================
        v1.0.0
        
        Added feature 1
        Added feature 2
        ===================================
        EOF
        
        gsed -E '0,/^={35}$/d; //Q' FILE
        

        输出:

        ▶ bash test.sh 
        v2.0.0
        
        Added feature 3
        Added feature 4
        

        【讨论】:

        • ▶ bash test.sh 有什么意义,因为我没有看到任何使用它的前言。
        • 抱歉,如果不清楚。我刚刚将我的测试脚本命名为 test.sh,然后使用bash test.sh 运行它。 只是我的提示。 @user3439894
        猜你喜欢
        • 2017-01-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-10-26
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多