如何在文件中搜索多行模式并打印匹配的捕获组?

时间:2015-06-17 01:07:07

标签: regex bash sed

我正试图在Bundler的锁文件格式中查找BUNDLER VERSION的值。以下是示例Gemfile.lock的尾部:

  thin
  turbolinks (>= 2.5.2)
  typogruby
  unicorn
  xray-rails (>= 0.1.15)

BUNDLED WITH
   1.10.4

鉴于上述文件,我想要一个输出1.10.4的简单bash单行程序。换句话说,比如:

cat Gemfile.lock | [magic here] # => 1.10.4

我希望有一个适用于Mac OS X和常见Linux发行版的解决方案,而无需安装任何特殊工具。

到目前为止,我已经发现我需要这样的正则表达式:

/^BUNDLED WITH\n   (\S+)$/

我如何" grep"这个模式的文件只打印捕获组?

我调查sed并很快感到沮丧。似乎sed不能轻易处理跨越多行的模式。

加成:

较早版本的锁定文件格式没有BUNDLER VERSION。理想情况下,如果模式不匹配,脚本将输出特殊值。

3 个答案:

答案 0 :(得分:2)

这可能适合你(GNU sed):

sed -n '/^BUNDLED WITH/{n;s/\s*//p}' file

在找到所需的字符串后,获取下一行并删除该行前面的空白区域并打印。

答案 1 :(得分:1)

这个解决方案需要Ruby,但是完成了工作:

ruby -e 'puts $<.read[/^BUNDLED WITH\n   (\S+)$/, 1] || "NOT FOUND"' Gemfile.lock

答案 2 :(得分:1)

与potong相同的奖金:

sed -n '/^BUNDLED WITH/{n;s/[ \t]*//g;h;};${g;/./!{s/.*/not found/;};p;};' file

细节:

n选项可以打开静音模式。在此模式下,不再自动显示行,但您可以使用p命令显式显示行。

/^BUNDLED WITH/ {  # condition: if a line starts with "BUNDLED WITH" then:
    n;             # overwrite the pattern space with the next line
    s/[ \t]*//g;   # replace all white-spaces with nothing (remove them)
    h;             # store the pattern space content in the buffer
};

$ {                # condition: When the last line is reached then:
    g;             # replace the pattern space with the buffer content
    /./! {               # condition: if the pattern space is "empty" then:
        s/.*/not found/; # replace the pattern space with "not found"
    };
    p; # print the pattern space
};

注意:您可以更明确地使用描述版本号的模式(如/./!或与锚点相同的模式),而不是测试存储的部分是否为空/[0-9][0-9]*\(\.[0-9][0-9]*\)*/!。 / p>