【问题标题】:sed bracket expression and capture groupsed 括号表达式和捕获组
【发布时间】:2017-02-26 01:58:03
【问题描述】:

我有以下一组需要通过 sed 处理的字符串:

start-pattern
[SYSTEM] capture ............................... FAIL [  2.825 s]
[SYSTEM] capture ............................... FAIL [  2.825 s]
[DEBUG] capture :: capture :: capture .......... FAIL [  0.866 s]
[DEBUG] capture :: me :: capture capture capture FAIL [  0.876 s]
[DEBUG] capture-me ............................. FAIL [  0.361 s]
end-pattern

我想写一个 sed 表达式(如果可能的话最好使用 sed)来获取[DEBUG] || 之间的所有字符串[SYSTEM]FAIL [.*] 用于失败的测试用例的每一行,不包括空格 和句点 . 以及文本 {start,end}-pattern 之间的 AND。

上述文本的输出应为以下一项或多项:

capture
capture
capture::capture::capture
capture::me::capture capture capture
capture-me

这是我尝试过的,但不适用于所有行:

sed -e 's/\[DEBUG\] \(.*\) :: \(.*\) :: \(.*\) \([^.]FAIL \[.*\]) \[.*/\1::\2::\3::\4/' -e 's/\[SYSTEM\] \(.*\) \..*/\1/'

【问题讨论】:

  • 对问题做了一个小修改,我需要处理开始和结束模式之间的所有行
  • start-patternend-pattern 看起来怎么样?它们的实际值是多少?
  • 抱歉!这些是确切的关键字而不是模式
  • 它们的名字是否准确地称为start-patternend-pattern,字面意思是?
  • 你不能接受 Perl-one-liner 吗?很短很简单

标签: shell awk sed


【解决方案1】:

以下是如何在任何 UNIX 系统上清晰、简单、稳健、高效且可移植地完成您的要求:

$ cat tst.awk
/start-pattern/ { inBlock=1 }
inBlock {
    if ( sub(/^\[(DEBUG|SYSTEM)\]/,"") && sub(/FAIL.*/,"") ) {
        gsub(/[[:space:].]/,"")
        print
    }
}
/end-pattern/ { inBlock=0 }

$ awk -f tst.awk file
capture
capture
capture::capture::capture
capture::me::capturecapturecapture
capture-me

请注意,您说您想要输出excluding spaces and period .,因此上面的“捕获”之间没有空格。如果您真正想要的只是排除 ::s 周围和输出行的开头/结尾处的空格,那么这只是一个调整:

$ cat tst.awk
/start-pattern/ { inBlock=1 }
inBlock {
    if ( sub(/^\[(DEBUG|SYSTEM)\]/,"") && sub(/FAIL.*/,"") ) {
        gsub(/[[:space:]]*::[[:space:]]*/,"::")
        gsub(/^[[:space:]]+|[[:space:]]+$|[.]/,"")
        print
    }
}
/end-pattern/ { inBlock=0 }

$ awk -f tst.awk file
capture
capture
capture::capture::capture
capture::me::capture capture capture
capture-me

【讨论】:

  • 第 4 行不匹配
  • 它与所要求的匹配,即输出排除空格。我添加了一个生成发布的预期输出的版本,以防万一这是真正想要的而不是错误。
  • 谢谢我明天试试..你能解释一下吗
  • excluding spaces and period . 我想被排除在所需文本之外。
  • 你能不能也看看这个问题,我想在awk中了解谁来做这个:stackoverflow.com/questions/42434040/…
【解决方案2】:

您可以使用以下内容:

$ gsed -nE 's/\[(DEBUG|SYSTEM)\] (.*) FAIL.*/\2/;{s/[.]//g;s/ :: /::/g;p;}' file                                                                                                                                                            
capture 
capture 
capture::capture::capture 
capture::me::capture capture capture
capture-me 

-n 选项自动停止 sed 打印行,-E 打开扩展正则表达式 (此选项在 GNU sed 中记录为 -r,但 -E 可用于 GNU 和 BSD sed) .

s              # Substitution command
/              # Start of match
\[             # Match a literal [
(DEBUG|SYSTEM) # Match DEBUG OR SYSTEM
\]             # Match a literal ] followed by a space
(.*)           # Match everything after and capture it
 FAIL.*        # Match a FAIL and everything after
/              # Stop match and start replacement
\2             # Replace with the second capture group
{              # If substitution matched applied following commands
s/[.]//g;      # Global substitution of literal .
s/ :: /::/g;   # Global substitution of spaces around literal ::
p;             # Print the result
}   

【讨论】:

  • @MarkReed 不确定它是什么时候引入的,但从我记事起,它就一直是一个无证支持的选项。
  • 不幸的是,当我使用 -ne 或 -nE 时出现同样的错误
  • @askb 您能否仅在示例输入上运行它并告诉我您是否收到错误消息?在此处查看它在 linux 上的 GNU sed 上的工作 ideone.com/SmQSqo
  • @askb 该行是以[DEBUG] 开头还是之前有空格?
  • @askb 尝试更新命令,它应该会产生您需要的输出。
【解决方案3】:

这适用于我的示例输入:

sed -nE '/^.*\[(SYSTEM|DEBUG)\] *(.*[^ ]) *FAIL.*$/{;s//\2/;s/[.]//g;p;}'
  1. -n 说“不要打印每一行”
  2. -E 打开扩展正则表达式(与| 交替使用;没有它,即使\| 也不可用)
  3. /^.*\[(SYSTEM|DEBUG)\] *(.*[^ ]) *FAIL.*$/ 匹配我们要查找的每一行的全部
  4. { 开始一个以分号分隔的命令块,以应用于匹配的行
  5. s//\2/ 表示用与第二组 (...) 之间匹配的部分替换与先前正则表达式匹配的任何内容
  6. s/[.]//g 删除所有句点。
  7. p 打印出一行
  8. } 终止块。

【讨论】:

  • capture::me::capturecapturecapture 应为capture::me::capture capture capture 外,其余行正常工作
  • 所以你想保留 internal 个空格。检查编辑的答案。
  • 对问题做了一个小修改,我需要处理开始和结束模式之间的所有行
【解决方案4】:

使用以下sed 命令组合:

sed -En 's/^\[(DEBUG|SYSTEM)\] (.+) FAIL.*$/\2/p' testfile | sed -En 's/(\.|\s(::)\s)/\2/gp'

输出:

capture 
capture 
capture::capture::capture 
capture::me::capture capture capture
capture-me 

第二个命令s/(\.|\s(::)\s)/\2/gp 将删除所有点. 并将' :: ' 替换为其修剪::


缩短的版本如下所示:

sed -En 's/^\[(DEBUG|SYSTEM)\] (.+) FAIL.*$/\2/;s/(\.|\s(::)\s)/\2/gp' testfile

【讨论】:

  • 对问题做了一个小修改,我需要处理开始和结束模式之间的所有行
【解决方案5】:

这也可以:

sed -n -e '/^\[SYSTEM\]/ ba; /^\[DEBUG\]/ ba; b;'
       -e ':a s/^\[.*\]\(.*\)FAIL.*/\1/; s/[ \.]*//g; \
           :c s/\(capture\)\(capture\)/\1 \2/g; tc; p;'
testcases.txt

输出:

capture
capture
capture::capture::capture
capture::me::capture capture capture
capture-me

如果行以[SYSTEM][DEBUG] 开头,则执行分支并完成替换并打印结果。否则什么都不做。

并且由于要求(在问题描述中未提及,但由希望的输出隐含给出),还有另一种构造可以在两次连续捕获之间保留空白。

更详细的:

1.) -n:如果p 命令未明确强制,则不打印模式空间。

2.) ba:跳转到标签a

3.) b: 跳转到脚本末尾。

4.) tc:如果已成功完成替换,则跳转到标签 c(自从读入最后一行并且自上次使用 tT 以来)。

【讨论】:

    【解决方案6】:
    awk -F'[]F]' '{gsub(/\./,"")gsub(/ /,"")gsub(/ec/,"e c");print $2}' file
    
    capture
    capture
    capture::capture::capture
    capture::me::capture capture capture
    capture-me
    

    【讨论】:

    • 谢谢我错过了。
    猜你喜欢
    • 2015-01-20
    • 1970-01-01
    • 2012-04-13
    • 2013-10-31
    • 2016-12-30
    • 2020-02-21
    • 2012-10-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多