【问题标题】:Match a string that could have a newline anywhere in it in - bash匹配一个可以在其中任何位置有换行符的字符串 - bash
【发布时间】:2014-01-24 23:40:58
【问题描述】:

我有一个包含如下数字的字符串:

\S2=number_goes_here\

号码可以是0.00000 及以上的任何数字。但是,该字符串中的任何地方都可能有换行符,我不完全确定如何匹配它。最终,我只想要这个数字。重要的是,该字符串位于可由该示例表示的大量文本中(S2 位于最后一行):

 1.454187\H,0,0.719618,3.525801,1.633708\H,0,-0.454651,2.80328,2.23844\
 Ru,0,0.025774,1.557599,-0.253913\\Version=EM64L-G09RevD.01\State=6-A\H
 F=-1238.5377983\S2=8.75446\S2-1=0.\S2A=8.750006\RMSD=2.314e-09\Dipole=

我愿意接受 bash、sed、awk、gawk;不管你有什么想法来解决这个问题。

编辑:

这是示例,下面的第一个答案似乎不适用于此示例。它只打印“2”。

 .631441,-2.132979\H,0,0.20151,-1.464802,-2.95553\H,0,0.377883,-2.50668
 5,-1.874761\\Version=EM64L-G09RevD.01\State=3-A\HF=-1265.9035096\S2=2.
 053325\S2-1=0.\S2A=2.000966\RMSD=1.590e-04\Dipole=0.7197616,-2.1253769

【问题讨论】:

    标签: regex bash sed awk


    【解决方案1】:
    grep -Po '(?<=S2=)[\d.]+' <(tr -d '\n' < file)
    

    给了

    8.75446
    

    【讨论】:

    • +1; OSX 用户(grep 不支持 -P - 因此不支持环视 - 并且 \d 不能在集合内使用):egrep -o '\\S2=[0-9.]+' &lt;(tr -d '\n' &lt; file) | cut -d'=' -f2
    • @mklement0 我试过这个,在 "S2=2.\n" 之后有一个换行符的字符串上,这不起作用,它只在新行之前拉。
    • 我在这里尝试了实际的答案,它没有正常工作,它可能不是一个真正的换行符吗?我已经编辑了我的问题以提供另一个示例。
    • @JM:您粘贴的输入数据还包含一个 space 字符。在每个\n 之后。如果也可以简单地删除所有空格,只需在tr -d '\n' 中添加一个空格,即:tr -d '\n '
    • @JM:很高兴听到这个消息;检查输入数据的快速提示:通过管道连接到 od -aod -c - 它会显示带有符号表示的控制字符的字节表示。
    【解决方案2】:

    您可以使用,以 slurp 模式读取整个文件,删除换行符并使用正则表达式进行搜索:

    perl -0777 -nE '
      $_ = join q||, split /\n/; 
      printf qq|%s\n|, $1 if m/\\S2=([\d.]+)/
    ' infile
    

    它产生:

    8.75446
    

    【讨论】:

      【解决方案3】:

      也可以只使用 bash,尽管这对于非常大的文件效果不佳。

      #!/bin/bash
      IFS=$'\n'
      string=$(<"test.txt")
      var=$(echo $string) # word-splitting will replace each newline with a space here
      
      while IFS= read -r word; do
        [[ $word =~ '\S2='([0-9]*\.[0-9]*)'\'  ]] && echo ${BASH_REMATCH[1]}
      done <<< "$var"
      

      例如

      > ./abovescript 
      8.75446
      

      【讨论】:

      • 抛开效率问题,您可以将您的方法简化为以下内容:IFS= read -d '' -r fileContents &lt;"test.txt"; [[ $fileContents =~ '\S2='([0-9]*\.[0-9]*) ]] &amp;&amp; echo "${BASH_REMATCH[1]}"。这会将整个文件按原样读入变量$fileContents,然后匹配它。然而,还要注意,OP 说换行符可以是anywhere,所以更安全的方法是在匹配之前remove所有换行符。
      【解决方案4】:

      这里是gnu awk 版本(由于RS 有多个字符):

      awk -F'\' 'NR==2 {print $1}' RS="S2=" file
      8.75446
      

      适用于大多数awk的版本

      awk -F\\ '{for (i=1;i<=NF;i++) if ($i~/S2=/) {split($i,a,"=");print a[2]}}' file
      8.75446
      

      【讨论】:

        猜你喜欢
        • 2010-11-19
        • 2011-01-26
        • 2013-04-16
        • 2020-09-04
        • 2022-12-09
        • 1970-01-01
        • 1970-01-01
        • 2011-09-25
        • 1970-01-01
        相关资源
        最近更新 更多