【问题标题】:Circumvent the sed backreference limit \1 through \9绕过 sed 反向引用限制 \1 到 \9
【发布时间】:2011-05-18 02:46:29
【问题描述】:

sed 手册明确指出,可用于替换字符串的可用反向引用编号为 \1 到 \9。我正在尝试解析一个包含 10 个字段的日志文件。

我已经为它形成了正则表达式,但第十场比赛(以及之后的任何比赛)都无法访问。

在 KSH(或任何我可以移植到 shell 脚本的语言)中,有没有人有一种优雅的方法来规避这个限制?

【问题讨论】:

  • 您几乎可以使用任何脚本语言来编写单行代码。 perl -pe 's/yourregexhere/$1$2$3$4$5$6$7$8$9$10/'
  • 很有可能您可以使用不需要那么多反向引用的更简单的正则表达式。如果您显示一些示例数据和您想要的输出示例,我们可能会向您展示一种更简单的方法。
  • 听起来像是 awk 的工作——字段 10 是 $10

标签: regex shell sed backreference


【解决方案1】:

如果你有GNU awk,你可以控制更多事情。为此,您将需要 match(source,/regex/,array) 构造。

例子:

用于测试的示例输入:

 echo "$x"
p1=aaa,p2=bb,p3=cc,p4=dd,p5=ee,p6=ff,p7=gg,p8=hh,p9=ii,p10=jj

sed\9 之前工作正常:

echo $x |sed -r 's/p1=([^,]+).*p2=([^,]+).*p3=([^,]+).*p4=([^,]+).*p5=([^,]+).*p6=([^,]+).*p7=([^,]+).*p8=([^,]+).*p9=([^,]+)(.*)/\1 \2 \3 \4 \5 \6 \7 \8 \9/'
aaa bb cc dd ee ff gg hh ii

在添加\10sed坏了,它被认为是\1+0

echo $x |sed -r 's/p1=([^,]+).*p2=([^,]+).*p3=([^,]+).*p4=([^,]+).*p5=([^,]+).*p6=([^,]+).*p7=([^,]+).*p8=([^,]+).*p9=([^,]+).*p10=([^,]+)(.*)/\1 \2 \3 \4 \5 \6 \7 \8 \9 \10/'
aaa bb cc dd ee ff gg hh ii aaa0

awk 在添加超过 9 的任何反向引用时进行救援。这里添加了第 10 个引用:

echo "$x" |awk '{match($0,/p1=([^,]+).*p2=([^,]+).*p3=([^,]+).*p4=([^,]+).*p5=([^,]+).*p6=([^,]+).*p7=([^,]+).*p8=([^,]+).*p9=([^,]+).*p10=([^,]+)(.*)/,a);print a[1],a[2],a[3],a[4],a[5],a[6],a[7],a[8],a[9],a[10]}'
aaa bb cc dd ee ff gg hh ii jj

【讨论】:

    【解决方案2】:

    使用 -e 分割流,只要被替换的元素在你分割它们的组中。当我进行日期拆分以便将日期时间重新组织为 14 位数字字符串时,我必须将流拆分 3 次。

    echo "created: 02/05/2013 16:14:49" |  sed -e 's/^\([[:alpha:]]*: \)//' -e 's/\([0-9]\{2\}\)\(\/\)\([0-9]\{2\}\)\(\/\)\([0-9]\{4\}\)\( \)/\5\1\3/' -e 's/\([0-9]\{2\}\)\(\:\)\([0-9]\{2\}\)\(\:\)\([0-9]\{2\}\)/\1\3\5/'
    

    20130205161449

    【讨论】:

    • 很高兴知道您可以像这样拆分它,但在您的示例中,您不需要捕获要丢弃的部分。以下实现了相同的效果(-E 允许您在括号之前删除斜杠):sed -E -e 's/[[:alpha:]]*: ([0-9]{2})\/([0-9]{2})\/([0-9]{4}) ([0-9]{2}):([0-9]{2}):([0-9]{2})/\3\1\2\4\5\6/'
    【解决方案3】:

    考虑一个不需要使用正则表达式反向引用的解决方案。例如,如果您有一个简单的字段分隔符,请使用split,甚至使用 awk 代替 perl 进行处理。

    【讨论】:

      【解决方案4】:

      你能用 perl -pe 's/(match)(str)/$2$1/g;' 代替 sed 吗?绕过反向引用限制的方法是使用 sed 以外的东西。

      另外,我想你可以分两步进行替换,但我不知道你的模式,所以我无法帮助你。

      【讨论】:

      • 谢谢你,这很好。现在我需要弄清楚如何动态生成模式并从 ksh 脚本运行此命令,但这是另一天的问题。
      【解决方案5】:

      您要求的是 shell 脚本解决方案 - 这意味着您不仅限于使用 sed,对吗?大多数 shell 都支持数组,所以也许您可以将行解析为 shell 数组变量?如果需要,您甚至可以多次解析同一行,每次通过时提取不同的信息位。

      这样可以吗?

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2010-11-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-10-23
        • 1970-01-01
        • 1970-01-01
        • 2013-10-22
        相关资源
        最近更新 更多