【问题标题】:How do I capture strings between a string match and a new line while ignoring newline and space in between in bash?如何在字符串匹配和换行符之间捕获字符串,同时忽略 bash 中的换行符和空格?
【发布时间】:2019-05-13 12:28:05
【问题描述】:

我有一堆清单文件,我正在尝试迭代以从中提取 Import-Packages。 Import-Package 是新行分隔的,后跟一个空格,用于所有连续的包导入,直到导入语句结束。 然后是一个新行,下一个属性(在本例中为 uri)没有空格。我只需要读取导入包属性,即导入包后跟所有换行符,然后是空格模式。

清单导入语句示例如下所示

Bnd-LastModified: 1494408636933
Bundle-ManifestVersion: 2
Import-Package: com.advantco.base,com.advantco.base.logging,com.advant
 co.base.mime,com.advantco.base.net,com.advantco.base.variablesubstitu
 tion,com.advantco.rest,com.advantco.rest.auth,com.advantco.rest.auth.
 oauth2,com.advantco.sugarcrm.core,com.advantco.sugarcrm.core.adapter,
 com.advantco.sugarcrm.core.error,com.advantco.sugarcrm.core.iface,com
 .advantco.sugarcrm.core.object,com.advantco.sugarcrm.core.object.meta
 data,com.advantco.sugarcrm.core.rest,com.advantco.sugarcrm.core.rest.
 auth,com.advantco.sugarcrm.core.rest.metadata,com.advantco.sugarcrm.c
 ore.rest.op,com.advantco.sugarcrm.core.rest.op.v10,com.advantco.sugar
 crm.core.rest.parser,com.advantco.sugarcrm.core.rest.parser.object,co
 m.advantco.sugarcrm.core.rest.parser.xml,com.advantco.sugarcrm.core.r
 est.service,com.advantco.sugarcrm.core.result,com.advantco.sugarcrm.c
 ore.result.v10,com.advantco.sugarcrm.core.service,com.advantco.sugarc
 rm.core.util,com.advantco.sugarcrm.core.xml,javax.activation,javax.cr
 ypto,javax.crypto.spec,javax.mail,javax.xml.bind,javax.xml.parsers,ja
 vax.xml.stream,javax.xml.transform,javax.xml.transform.dom,javax.xml.
 transform.stream,org.apache.commons.codec.binary,org.apache.commons.c
 ollections4.map,org.apache.commons.httpclient,org.apache.commons.http
 client.util,org.json
Require-Capability: osgi.ee;filter:="(&(osgi.ee=JavaSE)(version=1.6))"
Tool: Bnd-3.3.0.201609221906
Export-Package: com.advantco.sugarcrm.core;uses:="com.advantco.base.lo
 gging,com.advantco.sugarcrm.core.object";version="1.0.0",com.advantco
 .sugarcrm.core.adapter;uses:="com.advantco.base,com.advantco.base.log
 ging,com.advantco.base.net,com.advantco.base.variablesubstitution,com
 .advantco.sugarcrm.core,com.advantco.sugarcrm.core.error,com.advantco
 .sugarcrm.core.object,com.advantco.sugarcrm.core.object.metadata";ver
 sion="1.0.0",com.advantco.sugarcrm.core.error;version="1.0.0",com.adv
 antco.sugarcrm.core.iface;uses:="com.advantco.sugarcrm.core.error,com
 .advantco.sugarcrm.core.object";version="1.0.0",com.advantco.sugarcrm
 .core.object;uses:="com.advantco.base,com.advantco.base.mime,com.adva
 ntco.base.net,com.advantco.sugarcrm.core.error,com.advantco.sugarcrm.

Uri 或所需功能或导出包不能硬编码,可能是 Import-Package 之后的其他标志,所以我需要阅读所有行,包括 Import-Package 和所有新行,然后是导入包后面的空格,直到我得到一行后跟一个新的属性字段,而不是前面的空格(不一定是给定的 Header)。

输出如下

Import-Package: com.advantco.base,com.advantco.base.logging,com.advant
 co.base.mime,com.advantco.base.net,com.advantco.base.variablesubstitu
 tion,com.advantco.rest,com.advantco.rest.auth,com.advantco.rest.auth.
 oauth2,com.advantco.sugarcrm.core,com.advantco.sugarcrm.core.adapter,
 com.advantco.sugarcrm.core.error,com.advantco.sugarcrm.core.iface,com
 .advantco.sugarcrm.core.object,com.advantco.sugarcrm.core.object.meta
 data,com.advantco.sugarcrm.core.rest,com.advantco.sugarcrm.core.rest.
 auth,com.advantco.sugarcrm.core.rest.metadata,com.advantco.sugarcrm.c
 ore.rest.op,com.advantco.sugarcrm.core.rest.op.v10,com.advantco.sugar
 crm.core.rest.parser,com.advantco.sugarcrm.core.rest.parser.object,co
 m.advantco.sugarcrm.core.rest.parser.xml,com.advantco.sugarcrm.core.r
 est.service,com.advantco.sugarcrm.core.result,com.advantco.sugarcrm.c
 ore.result.v10,com.advantco.sugarcrm.core.service,com.advantco.sugarc
 rm.core.util,com.advantco.sugarcrm.core.xml,javax.activation,javax.cr
 ypto,javax.crypto.spec,javax.mail,javax.xml.bind,javax.xml.parsers,ja
 vax.xml.stream,javax.xml.transform,javax.xml.transform.dom,javax.xml.
 transform.stream,org.apache.commons.codec.binary,org.apache.commons.c
 ollections4.map,org.apache.commons.httpclient,org.apache.commons.http
 client.util,org.json

然后我可以去掉新的线条看起来像

Import-Package:com.advantco.base,com.advantco.base.logging,com.advantco.base.mime,com.advantco.base.net,com.advantco.base.variablesubstitution,com.advantco.rest,com.advantco.rest.auth,com.advantco.rest.auth.oauth2,com.advantco.sugarcrm.core,com.advantco.sugarcrm.core.adapter,com.advantco.sugarcrm.core.error,com.advantco.sugarcrm.core.iface,com.advantco.sugarcrm.core.object,com.advantco.sugarcrm.core.object.metadata,com.advantco.sugarcrm.core.rest,com.advantco.sugarcrm.core.rest.auth,com.advantco.sugarcrm.core.rest.metadata,com.advantco.sugarcrm.core.rest.op,com.advantco.sugarcrm.core.rest.op.v10,com.advantco.sugarcrm.core.rest.parser,com.advantco.sugarcrm.core.rest.parser.object,com.advantco.sugarcrm.core.rest.parser.xml,com.advantco.sugarcrm.core.rest.service,com.advantco.sugarcrm.core.result,com.advantco.sugarcrm.core.result.v10,com.advantco.sugarcrm.core.service,com.advantco.sugarcrm.core.util,com.advantco.sugarcrm.core.xml,javax.activation,javax.crypto,javax.crypto.spec,javax.mail,javax.xml.bind,javax.xml.parsers,javax.xml.stream,javax.xml.transform,javax.xml.transform.dom,javax.xml.transform.stream,org.apache.commons.codec.binary,org.apache.commons.collections4.map,org.apache.commons.httpclient,org.apache.commons.httpclient.util,org.json

我正在尝试这个,但它似乎不适用于导入包后面的标头很小的情况。 (这里是 Import-Packge: package-names ...... Require-Capability: 稍后但在某些情况下它的 Import-Packge: package-names ...... url: 然后被捕获。)

`sed -n -e '/Import-Package/,/[A-Z]/ p'` 

但如果 Manifest 是这样的

Bnd-LastModified: 1494408636933
Bundle-ManifestVersion: 2
Import-Package: com.advantco.base,com.advantco.base.logging,com.advant
 co.base.mime,com.advantco.base.net,com.advantco.base.variablesubstitu
 tion,com.advantco.rest,com.advantco.rest.auth,com.advantco.rest.auth.
 oauth2,com.advantco.sugarcrm.core,com.advantco.sugarcrm.core.adapter,
 com.advantco.sugarcrm.core.error,com.advantco.sugarcrm.core.iface,com
 .advantco.sugarcrm.core.object,com.advantco.sugarcrm.core.object.meta
 data,com.advantco.sugarcrm.core.rest,com.advantco.sugarcrm.core.rest.
 auth,com.advantco.sugarcrm.core.rest.metadata,com.advantco.sugarcrm.c
 ore.rest.op,com.advantco.sugarcrm.core.rest.op.v10,com.advantco.sugar
 crm.core.rest.parser,com.advantco.sugarcrm.core.rest.parser.object,co
 m.advantco.sugarcrm.core.rest.parser.xml,com.advantco.sugarcrm.core.r
 est.service,com.advantco.sugarcrm.core.result,com.advantco.sugarcrm.c
 ore.result.v10,com.advantco.sugarcrm.core.service,com.advantco.sugarc
 rm.core.util,com.advantco.sugarcrm.core.xml,javax.activation,javax.cr
 ypto,javax.crypto.spec,javax.mail,javax.xml.bind,javax.xml.parsers,ja
 vax.xml.stream,javax.xml.transform,javax.xml.transform.dom,javax.xml.
 transform.stream,org.apache.commons.codec.binary,org.apache.commons.c
 ollections4.map,org.apache.commons.httpclient,org.apache.commons.http
 client.util,org.json
url:http://sample.org

然后 sample.org 也被捕获。

【问题讨论】:

    标签: bash awk sed git-bash


    【解决方案1】:

    很多awk 回复,但这在sed 中也是完全可行的。

    如果您只想按原样打印块:

    $: sed -n '
     /^Import-Package: /,/^[^ ]/ {
        /^Import-Package:/ p;
        /^ / p;
     }
    ' infile
    

    在 GNU sed 中可以全部堆叠在一行上。

    $: sed -n '/^Import-Package: /,/^[^ ]/ { /^Import-Package:/ p; /^ / p; }' infile
    

    解释

    $: sed -n ' ...     ' infile
    

    使用sed-n 来防止任何输出,除非通过显式命令;从(在此示例中)一个名为 infile 的文件中读取,根据需要进行调整。在单引号内,程序显示:

     /^Import-Package: /,/^[^ ]/ {
        /^Import-Package:/ p; 
        /^ / p;
     }
    

    从以Import-Package: 开头的任何行开始,并继续以任何非空格开头的任何后续行(这里,明确 一个空格字符),执行此开头的所有命令- 大括号直到匹配的紧卷曲。

    在该块中,对于以Import-Package: 开头的任何行,打印它。对于任何以空格开头的行,打印它。

    在任何以非Import-Package: 开头的非空格开头的行上都没有打印命令,因此如果在其下方开始有另一个块,它将不会打印那个块,并且切换将退出范围,因此它不会打印任何其他内容,除非另一个 Import-Package: 块开始。

    如果块结束文件,代码范围永远不会超出范围,所以它会一直打印,直到记录用完为止。

    如果您希望它在一行上打印所有块并删除空格 -

    $: sed -n '
     /^Import-Package: /,/^[^ ]/ {
        /^Import-Package:/ { h; d; }
        /^ / H;
        /^[^ ]/ { s/.*//; x; s/\n* //g; p; d;   }
        $       {         x; s/\n* //g; p; d;   }
     }
    ' infile
    

    对于从/^Import-Package: / 到任何非空格首字符的行,

    • 如果行以Import-Package: 开头,则将其替换为保持空间,并将其从模式空间中删除以触发干净的下一次读取。
    • 如果该行以空格开头,请将其添加到保留空格中
    • 如果一行以非空格开头,则使用s/.*// 擦洗它;其余的也适用于最后一行($),所以在任何一种情况下,x 将累积的保持空间放回模式空间(从技术上讲,它交换它们),s/\n* //g 将所有换行空间序列替换为空(删除它们),p 打印该行,d 删除它以获得一个干净的缓冲区以开始下一个循环(在文件末尾退出)。

    其余的都是不必要的选择,

    ...但是因为我第一次把请求读错了,以防它可能对其他人有帮助。

    如果你想把所有的包分开并打印在自己的一行上(这是我最初认为你的意思),那么

    $: sed -n '
     $ {
      /^Import-Package: / {
        s/^Import-Package: //; s/,/\n/g; p;
      }
     }
     /^Import-Package: /,/^[^ ]/ {
        /^Import-Package:/ { s/^Import-Package://; h; n; }
        /^ / H;
        /^[^ ]/ { s/.*//; x; s/\n* //g; s/,/\n/g; p; d;   }
        $       { s/.*//; x; s/\n* //g; s/,/\n/g; p; d;   }
     }
    ' infile
    

    如果Import-Package: 不可能从文件的最后一行开始,您可以删除顶部的$ 块。如果它不是文件中的最后一个块,您也可以删除主块底部的$ 行。

    参考GNU sed manual 用于每个命令的细分 - 如果您愿意,我会回来详细说明。

    【讨论】:

      【解决方案2】:

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

      sed -n '/^Import-Package:/{:a;N;s/\n //;ta;P;D}' file
      

      使用-n 选项显式打印文本。从以Import-Package: 开头的第一行开始,追加以下行。如果附加的行以空格开头,请将其删除,如果替换成功,则重复直到附加的行不匹配。然后打印模式空间的第一行,然后删除模式空间的第一行,重复。

      【讨论】:

        【解决方案3】:

        我的假设:

        • “Import-Package:”行可能从文件中间开始。
        • 下一个属性并不总是“uri”。

        那么怎么样:

        awk '/^Import-Package:/,!/^Import-Package:/&&!/^ / {
             if (!line || sub(/^ /, "")) line = line $0}
             END {print line}
        ' sample.txt
        

        它从“Import-Package:”行读取直到下一个属性行(被丢弃),通过删除前导空格来连接这些行。

        【讨论】:

        • 好的,我已经更新了我的答案,因此无论AWK 版本如何,它都能正常工作。它应该适用于您的两个示例。
        【解决方案4】:

        使用 Perl

        perl -0777 -ne ' s/.*(Import-Package:.+?)\n(?=\S)(.*)/$1/smog; print ' sameer.pkg
        

        删除换行符

        perl -0777 -ne ' s/.*(Import-Package:.+?)\n(?=\S)(.*)/$1/smog; print ' sameer.pkg | tr -d '\n'
        
        Import-Package: com.advantco.base,com.advantco.base.logging,com.advant co.base.mime,com.advantco.base.net,com.advantco.base.variablesubstitu tion,com.advantco.rest,com.advantco.rest.auth,com.advantco.rest.auth. oauth2,com.advantco.sugarcrm.core,com.advantco.sugarcrm.core.adapter, com.advantco.sugarcrm.core.error,com.advantco.sugarcrm.core.iface,com .advantco.sugarcrm.core.object,com.advantco.sugarcrm.core.object.meta data,com.advantco.sugarcrm.core.rest,com.advantco.sugarcrm.core.rest. auth,com.advantco.sugarcrm.core.rest.metadata,com.advantco.sugarcrm.c ore.rest.op,com.advantco.sugarcrm.core.rest.op.v10,com.advantco.sugar crm.core.rest.parser,com.advantco.sugarcrm.core.rest.parser.object,co m.advantco.sugarcrm.core.rest.parser.xml,com.advantco.sugarcrm.core.r est.service,com.advantco.sugarcrm.core.result,com.advantco.sugarcrm.c ore.result.v10,com.advantco.sugarcrm.core.service,com.advantco.sugarc rm.core.util,com.advantco.sugarcrm.core.xml,javax.activation,javax.cr ypto,javax.crypto.spec,javax.mail,javax.xml.bind,javax.xml.parsers,ja vax.xml.stream,javax.xml.transform,javax.xml.transform.dom,javax.xml. transform.stream,org.apache.commons.codec.binary,org.apache.commons.c ollections4.map,org.apache.commons.httpclient,org.apache.commons.http client.util,org.json
        

        【讨论】:

          【解决方案5】:

          编辑: 因为 OP 告诉 uri 字符串不应该被硬编码,所以现在添加这个解决方案。

          awk '
          /Import-Package/{
            flag=1
            val=$0
            next
          }
          flag && /^ / && NF{
            gsub(/^ /,"")
            val=val?val $0:$0
            next
          }
          flag && !/^ / && NF{
            print val
            flag=val=""
          }'  Input_file
          

          输出如下。

          Import-Package: com.advantco.base,com.advantco.base.logging,com.advantco.base.mime,com.advantco.base.net,com.advantco.base.variablesubstitution,com.advantco.rest,com.advantco.rest.auth,com.advantco.rest.auth.oauth2,com.advantco.sugarcrm.core,com.advantco.sugarcrm.core.adapter,com.advantco.sugarcrm.core.error,com.advantco.sugarcrm.core.iface,com.advantco.sugarcrm.core.object,com.advantco.sugarcrm.core.object.metadata,com.advantco.sugarcrm.core.rest,com.advantco.sugarcrm.core.rest.auth,com.advantco.sugarcrm.core.rest.metadata,com.advantco.sugarcrm.core.rest.op,com.advantco.sugarcrm.core.rest.op.v10,com.advantco.sugarcrm.core.rest.parser,com.advantco.sugarcrm.core.rest.parser.object,com.advantco.sugarcrm.core.rest.parser.xml,com.advantco.sugarcrm.core.rest.service,com.advantco.sugarcrm.core.result,com.advantco.sugarcrm.core.result.v10,com.advantco.sugarcrm.core.service,com.advantco.sugarcrm.core.util,com.advantco.sugarcrm.core.xml,javax.activation,javax.crypto,javax.crypto.spec,javax.mail,javax.xml.bind,javax.xml.parsers,javax.xml.stream,javax.xml.transform,javax.xml.transform.dom,javax.xml.transform.stream,org.apache.commons.codec.binary,org.apache.commons.collections4.map,org.apache.commons.httpclient,org.apache.commons.httpclient.util,org.json
          


          第一个解决方案:考虑到您的实际 Input_file 与显示的示例相同,请您尝试以下操作。

          awk '
          /^uri/{
            flag=""
          }
          /^Import/{
            flag=1
          }
          flag{
            sub(/^ +/,"")
            val=val?val $0:$0
          }
          END{
            print val
          }' Input_file
          

          第二个解决方案: 在此处使用RS 添加解决方案。

          awk -v RS="uri:" 'FNR==1{gsub(/\n|\n +/,"");print}'  Input_file
          

          第三种解决方案:在这里都使用RSFS

          awk -v RS="" -v FS="uri:" '{gsub(/\n|\n +/,"",$1);print $1}'  Input_file
          

          第 4 个解决方案: 使用 match 关键字和 awk 再添加 1 个解决方案。

          awk -v RS=""  -v FS="\n" 'match($0,/Import.*uri/){val=substr($0,RSTART,RLENGTH);gsub(/\n|\n +|uri$/,"",val);print val}' Input_file
          

          注意: 如果您只有 1 次这种类型的行要打印,那么您也可以在上述两个代码的 print 语句之后添加 exit

          【讨论】:

          • Uri 不能被硬编码,可能是 Import-Package 之后的其他标志,所以我需要读取所有行,包括 Import-Package,所有新行后跟空格,直到我得到一个 ned 行,然后是一个新行属性字段(不一定是 uri)。
          • @Sameer,你为什么不在单发中提及所有条件,不知道为什么我们也因为努力提供帮助而获得了 DOWN VOTE。
          • @Sameer,很简单,通过提供输入样本和输出样本以简单的方式提出问题(不要频繁更改问题)。在投票方面,如果有人不清楚,那么给张贴者带来怀疑的好处,而不是给予反对票。如果答案确实需要任何改进,请投反对票。如果您愿意,请尝试通过投票来鼓励人们。让我检查一下您的新输入,如果可能,请删除对任何试图帮助您的人的反对票。
          • 如果您打算对任何未能获得您想要的结果的人投反对票,您最好在第一次就提供完美的问题...
          • @RavinderSingh13 Stackverflow 只会让我在有编辑后投票支持,它之前不存在,但现在它在那里,所以我支持 :)
          猜你喜欢
          • 2017-12-30
          • 1970-01-01
          • 1970-01-01
          • 2013-11-19
          • 1970-01-01
          • 2016-12-08
          • 1970-01-01
          • 2015-08-03
          • 1970-01-01
          相关资源
          最近更新 更多