【问题标题】:'+' (one or more occurrences) not working with 'sed' command'+'(出现一次或多次)不适用于 'sed' 命令
【发布时间】:2018-04-19 05:10:28
【问题描述】:

我正在尝试通过删除不必要的空格、空行以及括号与它们之间的空格来平衡我的代码,所以:

    int a = 4;
    if ((a==4) ||   (b==5))

    a++   ;

应该改为:

    int a = 4;
    if ( (a==4) || (b==5) )
    a++ ;

它确实适用于括号和空行。但是,它忘记了将多个空格减少到一个空格:

    int a = 4;
    if ( (a==4) ||   (b==5) )
    a++    ;

这是我的脚本:

    #!/bin/bash
    # Script to refine code
    #
    filename=read.txt

    sed 's/((/( (/g' $filename > new.txt
    mv new.txt $filename

    sed 's/))/) )/g' $filename > new.txt
    mv new.txt $filename

    sed 's/ +/ /g' $filename > new.txt
    mv new.txt $filename

    sed '/^$/d' $filename > new.txt
    mv new.txt $filename

另外,有没有办法让这个脚本更简洁,例如删除或减少命令数量?

【问题讨论】:

  • 顺便说一下,在 BRE 中你可以使用 \{1,\} 代替 +
  • @cdarke,我不明白,这也给你多个空格吗?
  • / \{1,\}/ 表示“一个或多个空格”,是的。
  • @cdarke 你的回答很棒。我编辑了接受的答案以包含您的有用评论!

标签: macos bash sed


【解决方案1】:

如果您使用的是GNU sed,那么您需要使用sed -r,它强制sed 使用扩展的正则表达式,包括+ 的所需行为。见man sed

-r, --regexp-extended

       use extended regular expressions in the script.

如果您使用的是 OS X sed,这同样适用,但是您需要使用 sed -E

-E      Interpret regular expressions as extended (modern) regular expressions
        rather than basic regular regular expressions (BRE's).

【讨论】:

  • -r 似乎是一个非法选项,但我做了一个 man sed 以使用扩展正则表达式,它显示为“-E”。试过了,宾果游戏!有效!谢谢!但我现在很困惑,使用 '*' 有效,但使用 '+' 我必须使用 -E 标志?
  • 您使用的是 OS X 是否正确? -r 适用于 GNU sed,但 OS X sed 确实需要 -E 才能使用扩展的(现代)正则表达式。两者都区分了 basicmodern 正则表达式,+ 被解释为 sedbasic 功能中的普通字符。请参阅this reference过时的 (''basic'') 正则表达式在几个方面有所不同 (...) '+' 和 '?'是普通字符 (...).
  • 是的,在 OSX 中使用 -E 而不是 -r
  • 如果您在 OS X 上使用自制软件,您可以安装 GNU 版本的 sed (gnu-sed) 并使用 gsed 命令模拟正常行为。 (我这样做是为了避免学习 UNIX/BSD sed 的不同行为)
  • @ThorSummoner:不仅仅是 *nix,还包括 .Net 引擎、JavaScript、Perl(现在与 PCRE 不同)、Python、Java 等...见choonsiong.com/public/books/…
【解决方案2】:

您必须在+ 前面加上\,否则sed 会尝试匹配字符+ 本身。

为了让脚本“更智能”,你可以将所有的表达式累积在一个 sed 中:

sed -e 's/((/( (/g' -e 's/))/) )/g' -e 's/ \+/ /g' -e '/^$/d' $filename > new.txt

sed 的某些实现甚至支持-i 选项,该选项可以就地更改文件

【讨论】:

  • 前面的 \ 不起作用.. -i 标志给出错误:sed: -i may not be used with stdin
  • 积累不起作用:(我找不到如何在线执行下一个 sed 命令,使用 'awk' 是不是更好?如果是这样,如何?感谢任何帮助。
  • @Siddhartha: -i 仅适用于文件,不适用于标准输入。你怎么能改变标准输入?您也可以尝试使用分号进行累加:sed -e 's///;s///;...'
  • 好的,所以我得到了积累,但我无法让 -E 标志适合任何地方!:
  • 我不认为 MacOS sed 支持多个 -e 选项。在各个脚本命令之间使用分号或换行符,并将它们全部放在一个带引号的字符串中。同样在 MacOS 上,-i 选项需要一个参数;如果你不想备份,你可以给它一个空字符串。所以sed -i '' -E 's///;s///;...' "$filename"
【解决方案3】:

有时,-r 和 -e 不起作用。 我正在使用 sed 4.2.1 版,它们根本不适合我。

一个快速的技巧是改用 * 运算符。 所以假设我们想用一个空格替换所有多余的空格字符: 我们想做:

sed 's/ +/ /'

但我们可以改用这个:

sed 's/  */ /'

(注意双空格)

【讨论】:

  • 这是我一直使用的。它适用于一切。这不是真正的hack,只是对“零或更多”的修改-“一加零或更多”=“一或更多”
【解决方案4】:

可能不是最干净的解决方案。但是如果你想避免-E-r 保持与两个版本的sed 兼容,你可以做一个重复字符cc* - 那是1 c 然后0 或更多c== 1或更多c's。

或者只使用@cdarke 建议的BRE 语法来匹配特定数字或模式c\{1,\}。排除逗号后的第二个数字表示 1 或更多。

【讨论】:

    【解决方案5】:

    这可能对你有用:

    sed -e '/^$/d' -e ':a' -e 's/\([()]\)\1/\1 \1/g' -e 'ta' -e 's/  */ /g' $filename >new.txt
    

    【讨论】:

      【解决方案6】:

      在 bash 前面;

      首先我做了一个脚本test.sh

      猫测试.sh

      #!/bin/bash
      while IFS='' read -r line || [[ -n "$line" ]]; do
          echo "Text read from file: $line"
          SRC=`echo $line | awk '{print $1}'`
          DEST=`echo $line | awk '{print $2}'`
          echo "moving $SRC to $DEST"
          mv $SRC $DEST || echo "move $SRC to $DEST failed" && exit 1
      done < "$1"
      

      然后我们制作一个数据文件和一个测试文件aaa.txt

      cat aaa.txt
      <tag1>19</tag1>
      <tag2>2</tag2>
      <tag3>-12</tag3>
      <tag4>37</tag4>
      <tag5>-41</tag5>
      

      然后测试并显示结果。

      bash test.sh list.txt 
      Text read from file: aaa.txt bbb.txt
      moving aaa.txt to bbb.txt
      

      【讨论】:

        猜你喜欢
        • 2015-06-04
        • 2021-06-17
        • 2020-12-09
        • 1970-01-01
        • 2013-11-04
        • 2015-08-28
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多