【问题标题】:Sed not reading multiline input?Sed不读取多行输入?
【发布时间】:2015-02-14 20:20:32
【问题描述】:

我有一些文字如下:

path => ["/home/Desktop/**/auditd.log",
        "/home/Desktop/**/rsyslog*.log",
        "/home/Desktop/**/snmpd.log",
        "/home/Desktop/**/kernel.log",
        "/home//Desktop/**/ntpd.log",
        "/home/Desktop/**/mysql*.log",
        "/home/Desktop/**/sshd.log",
        "/hme/Desktop/**/su.log",
        "/home/Desktop/**/run-parts(.log"
    ] 

我想提取[]里面的值,所以我这样做:

sed -n 's/.*\[\(.*\)\]/\1/p'

Sed 没有返回任何内容。

如果我执行sed -n 's/.*\[\(.*\)log/\1/p,它会正确返回[log 之间的字符串。

"/home/Desktop/**/auditd.",

所以它可以在行内搜索。

如何做到这一点?

编辑:

我创建了一个包含内容的文件:

path => [asd,masd,dasd
sdalsd,ad
asdlmas;ldasd
]

当我执行grep -o '\[.*\]' 时,它不起作用,但grep -o '\[.*' 这将返回第一行[asd,masd,dasd。所以它适用于单行而不是多行。

【问题讨论】:

  • sed 是面向行的。您的第一个模式与输入中的任何行都不匹配。
  • 那么如果必须提取多行,如何提取? Grep 还返回同一行的搜索
  • 如果您需要在行之间匹配内容,请使用awk 之类的东西或一些可以真正理解输入格式的工具。 this question 的最后一点向您展示了一个非常方便的用于行范围处理的 awk 模式。
  • 我确实使用了 awk:awk '/\[/,/\]/',但它返回的输出与输入相同,因为它在输出中包含 path =>
  • 这个文件的输出是什么?似乎是一种数据结构

标签: regex sed multiline


【解决方案1】:

您可以使用awk 来做到这一点,方法是将.*[] 或空白替换为空:

$ awk '{gsub(/.*\[|\]| /, ""); print}' filename

"/home/Desktop/**/auditd.log",
"/home/Desktop/**/rsyslog*.log",
"/home/Desktop/**/snmpd.log",
"/home/Desktop/**/kernel.log",
"/home//Desktop/**/ntpd.log",
"/home/Desktop/**/mysql*.log",
"/home/Desktop/**/sshd.log",
"/hme/Desktop/**/su.log",
"/home/Desktop/**/run-parts(.log"

【讨论】:

    【解决方案2】:

    尝试这样做:

    $ grep -o '".*",?' file
    

    输出:

    "/home/Desktop/**/auditd.log",
    "/home/Desktop/**/rsyslog*.log",
    "/home/Desktop/**/snmpd.log",
    "/home/Desktop/**/kernel.log",
    "/home//Desktop/**/ntpd.log",
    "/home/Desktop/**/mysql*.log",
    "/home/Desktop/**/sshd.log",
    "/hme/Desktop/**/su.log",
    "/home/Desktop/**/run-parts(.log"
    
    • -o grep 只打印匹配的部分
    • " 是文字双引号
    • .* 什么都可以
    • "si 结束双引号
    • , 是文字双引号
    • ? 表示 o 或 1 次出现

    【讨论】:

    • 你能解释一下吗?
    • 好的。我明白了,它只捕获 "" , 。但是在其他一些情况下,当输入不同时,如何捕获多行??
    • 它不仅捕捉“”,还捕捉里面的东西。下一次,你必须调整正则表达式。
    • 我的意思是如果输入中没有特定的模式怎么办。就像上面的例子“.*,?”是一种模式,我们对此感到满意。如果我们必须捕获黑白文本 [ ] 但 [ ] 中的数据是随机的,该怎么办。在这种情况下,执行 .* 不适用于多行。那么如何实现呢?
    • 我创建了一个包含以下内容的文件:path => [asd,masd,dasd sdalsd,ad asdlmas;ldasd ] 当我执行grep -o '\[.*\]' 时,它不起作用但grep -o '\[.*' 这将返回第一行[asd,masd,dasd。所以它适用于单行而不是多行。
    【解决方案3】:

    好吧,我有点太慢了,但我认为如何将 sed 替换作为一个块而不是逐行应用于整个文件的问题值得一个普遍的答案,所以我会离开一个在这里。

    在您的具体情况下,您可以使用这种模式:

    sed -n 'H; $ { x; s/.*\[\(.*\)\].*/\1/; p; }' foo.txt
    

    一般的技巧是

    sed -n 'H; $ { x; s/pattern/replacement/flags; p; }' file
    

    这意味着:进入的每一行都附加到保持缓冲区(使用H 命令),并在文件末尾($),当整个文件都在保持缓冲区中时,括号之间的东西被执行。在该块中,保持缓冲区与模式空间 (x) 交换,然后完成替换,并打印模式空间中剩余的内容 (p)。

    编辑:这种简单形式的一个警告是,如果您的模式想要匹配文件的开头,它就不能正常工作;由于某些原因,第一次调用 sed 时,保持缓冲区并非完全为空(它包含一个空行)。如果这很重要,那么稍微复杂一点的表格

    sed -n '1 h; 1 !H; $ { x; s/pattern/replacement/flags; p; }' file
    

    修复它。这将在第一行使用h 而不是H,这会用模式空间覆盖保持缓冲区,而不是将模式空间附加到保持缓冲区。

    【讨论】:

    • s/.*\[ 可能会失败,因为第一个 .* 采用可能的最冗长的模式,所以直到最后一个 [ 之前,最后一个 ] 可能位于块的中间。我建议改用^[^[]*\[
    • 如果文件中有几对括号,则取决于OP想要匹配的内容,这是一个有效的点,是的。我只复制了 OP 的正则表达式。
    • 这是"/home/Desktop/**/run-parts(.log" 行,它让我写下评论怀疑其他特殊字符,如[ 可能在字符串中
    【解决方案4】:

    从您的样本中,也可能是(仅处理第一行和最后一行)

    sed '1s/^[^[]*\[//;$d' YourFile
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-07-24
      • 1970-01-01
      相关资源
      最近更新 更多