【问题标题】:Shell substitution/replace not working as expected with Perl and SED在 Perl 和 SED 中,Shell 替换/替换无法按预期工作
【发布时间】:2014-09-22 06:47:44
【问题描述】:

我有一些格式为:

Sys!CTP_Live83000_@DRS_named_error_out_1
EServerJTP!CTP_Live56000_@input_error_queue_205

我正在尝试从末尾删除“_number”,即“_1”和“_205”,但遇到了一些麻烦。

到目前为止,我已经提出了 2 个解决方案,但都没有达到我想要的效果

1) 使用 Perl,这会将字符串末尾的下划线和数字替换为空格,但它也会替换字符串中所有出现的 _。

...|/usr/bin/perl -pi -e 's/[_][0-9]*/ /g'

2) 使用 SED,这将保持字符串中的下划线完整,但仅删除(替换为空格)字符串末尾的下划线和第一个数字,在 2 位和 3 位数字的情况下,保留一些数字:

...|sed 's/[_][0-9]/ /'

这是在 Solaris 5.10 服务器上。

我做错了什么?谢谢!

【问题讨论】:

  • 您是要完全删除_number 还是用空格替换它?
  • 谢谢大家的回答,非常感谢。我尝试了所有 SED 解决方案,但我无法让它们中的任何一个工作,但 perl 解决方案确实有效。我不确定为什么 SED 解决方案不起作用,我过去在这台服务器上遇到过 SED 问题,我问过管理服务器的人是否安装了非标准版本的 SED,但他们确认它是 Solaris 捆绑的默认版本?
  • 我很惊讶我的解决方案不起作用,因为它实际上是与 Perl 答案相同的正则表达式,并且完全兼容 POSIX(因此应该适用于任何版本的 sed)。您可以sed --version了解您使用的版本。
  • @skamazin 理想情况下,我想用相同数量的空格替换“_number”,但是由于 SED 无法按预期工作的问题,我有点放弃了这个想法并与计划 B 一起去,就是简单地删除它。
  • 我刚刚查看了您的 SunOS 版本附带的 sed 版本的联机帮助页。我认为我的建议的问题可能是[:digit:] 字符类。我在回答中添加了另一个建议,我很想知道它是否有效!

标签: regex perl shell sed substitution


【解决方案1】:

sed 's/_[0-9][0-9]*$//' 应该可以解决问题

输出是:

    Sys!CTP_Live83000_@DRS_named_error_out
    EServerJTP!CTP_Live56000_@input_error_queue

诀窍是使用美元符号强制它找到行尾。

【讨论】:

    【解决方案2】:

    你可以拥有:

    sed 's/_[0-9]\+$//'
    

    这将匹配行尾的下划线 _ 和数字(一个或多个 (+) 数字 [0-9])或模式 ($)。

    当然你也可以使用字符列表:

    sed 's/_[[:digit:]]\+$//'
    

    启用-r 后,无需引用+:

    sed -r 's/_[0-9]+$//'
    sed -r 's/_[[:digit:]]+$//'
    

    您还可以选择添加一个额外的模式来捕获额外的尾随空格:

    sed -r 's/_[0-9]+[ \t\r]*$//'
    

    【讨论】:

      【解决方案3】:

      假设您的输入在file:

      sed -e 's/_[[:digit:]]\{1,\}$//' file 
      

      将删除下划线,后跟每行末尾的一位或多位数字。注意_ 不需要它自己的字符类[_]。这是 POSIX 兼容的,因此无论您的 sed 版本如何,都应该可以工作。如果输入通过管道传输到 sed,它也应该同样有效。

      在您的问题中使用[0-9]* 的问题在于,这意味着零 或更多,因此any 下划线将匹配完整表达式并被删除。


      看起来你的 sed 版本已经很旧了!与使用 POSIX 字符类 [:digit:] 相比,使用 [0-9] 可能会更成功:

      sed -e 's/_[0-9]\{1,\}//'
      

      我还删除了$ 行末尾的锚点,以防引起任何问题。

      【讨论】:

      • 后一个版本给出了想要的结果(与 Borodin 的 perl 命令完全相同)。感谢您的贡献以及有关 SED 版本的信息已经很旧了!以后我会记住这一点的。
      【解决方案4】:

      问题在于[0-9]* 允许零个或多个 位,从而允许您的正则表达式匹配裸下划线_。

      为确保至少有一位数字,您可以使用+ 而不是*。

      另外,/g 选项在这里不合适,因为您只想替换一次出现的模式,而如果您总是通过管道传递到此命令,则-i perl 选项是无关紧要的,因此给出了

      perl -pe 's/_[0-9]+/ /'
      

      【讨论】:

      • 可能值得一提的是,虽然-i 不会产生任何负面影响,但如果输入在 STDIN 上,它也可能会被删除(因为它似乎在问题中)。
      猜你喜欢
      • 2016-02-15
      • 1970-01-01
      • 2016-11-12
      • 1970-01-01
      • 2013-03-26
      • 2020-06-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多