【问题标题】:grep split and matchgrep 拆分和匹配
【发布时间】:2020-07-29 07:50:40
【问题描述】:

我需要使用 grep(或 shell/bash 中的 awk 等)解析 Keep a changelog format 中的 CHANGELOG 并获取最新版本([Unreleased] 标记之后的第一个版本)。

意思是,用块'\n##'分割这个文件,忽略第一个([Unreleased])并获取第二个(如果存在)。

使用nodeJS,它非常简单易读CHANGELOG.split(/\n## /)[2]; 但我不能让它与 grep 一起工作...grep -zoP -m 1 "(\n## .*)(\n## .*)?(\n## )?" CHANGELOG.md

即使使用(.|\n)+,我也无法使用多行创建正则表达式匹配组 由于几天以来我一直在使用它并一次又一次地尝试,Machine Learning 找到了这个##(?:[^be]+[^#]*###)+[^#]* 但是,对于“与\n## 进行块拆分”来说,它看起来太重了。

# Changelog
All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

## [1.0.0] - 2017-06-20
### Added
{...}

### Changed
{...}

### Removed
{...}

## [0.3.0] - 2015-12-03
{...}

我需要捕获块:

## [1.0.0] - 2017-06-20
### Added
{...}

### Changed
{...}

### Removed
{...}

更新 #1

我发现一个与(?=\n## .*?)(\n## .*?)(?=\n## |$) 一起工作(见regex101.com),现在只需要打印Match 2

有什么帮助吗?谢谢!

【问题讨论】:

    标签: regex bash file split grep


    【解决方案1】:

    这个 perl 单行器完成这项工作,它以“slurp”模式读取文件并打印您要查找的数据:

    perl -0777 -ane '/## \[Unreleased]\R\R\K##[\s\S]+(?=## \[\d)/ && print$&' logfile
    ## [1.0.0] - 2017-06-20
    ### Added
    {...}
    
    ### Changed
    {...}
    
    ### Removed
    {...}
    

    说明:

    /                       # regex delimiter
        ## \[Unreleased]        # literally
        \R\R                    # 2 linebreak
        \K                      # forget all we have seen until this position
        ##[\s\S]+               # 2 # followed by 1 or more any character including newline
        (?=## \[\d)             # positive lookahead, make sure we have ## [digit after (previous relaese)
    /                       # regex delimiter
    

    如果此正则表达式匹配,则打印匹配的内容print$&

    【讨论】:

    • 感谢您在 perl match one-liner 上给我指点。我搜索,但没有找到这个。我不能将其作为“解决方案”,因为正则表达式不匹配其他可能性(未发布可以为空或包含与发布相同的数据,并且第一个发布在文件末尾没有 ## 匹配)。但是您的回答点很多信息可以帮助我使正则表达式起作用! +1
    【解决方案2】:

    感谢@Toto 的回答,帮助我接近解决方案。

    我的结局是这样的:

    perl -0777 -ane '/## \[Unreleased][\s\S]+?\K(\n## [\s\S]+?)(?=\n## |$)/ && print$&' CHANGELOG.md

    【讨论】:

      【解决方案3】:

      Ed 可以做到这一点。

      #!/bin/sh
      
      cp CHANGELOG.md stack
      
      cat >> extract.ed << EOF
      /2017/
      .,\$w new-changelog.txt
      EOF
      
      cat >> ex2.ed << EOF
      /2015/
      -1
      .,\$d
      wq
      EOF
      
      ed -s stack < extract.ed
      ed -s new-changelog.txt < ex2.ed
      rm -v ./extract.ed ./ex2.ed
      

      【讨论】:

      • 我将在 gitlab-ci.yml 中使用 grep 作为 CI piepline,并且真的想让一个简单的提取字符串尽可能短。无论如何,谢谢你的建议。
      • 您的回复很亲切,值得赞赏。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-03-25
      • 2017-04-24
      • 2012-11-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多