【问题标题】:match repeated character in sed on mac在mac上匹配sed中的重复字符
【发布时间】:2018-07-15 16:47:24
【问题描述】:

我正在尝试查找 3 个或更多新行的所有实例,并仅用 2 个新行替换它们(想象一个包含太多空白的文件)。我正在使用 sed,但如果这样更容易,可以使用 awk 或类似方法来回答。

注意:我在 mac 上,所以 sed 与在 linux 上略有不同(BSD 与 GNU)

我的实际目标是换行,但我根本无法让它工作,所以为了简单起见,我尝试匹配 3 次或更多重复的 bla 并将其替换为 BLA

制作一个名为studt.txt的示例文件:

$ cat stupid.txt

blablabla
$

我的理解是你匹配 i 或更多的东西 使用正则表达式语法 thing{i,}
我已经尝试过这种变体来匹配 3 个 blas,但没有运气:

cat stupid.txt | sed 's/bla{3,}/BLA/g'      # simplest way
cat stupid.txt | sed 's/bla\{3,\}/BLA/g'    # escape curly brackets
cat stupid.txt | sed -E 's/bla{3,}/BLA/g'   # use extended regular expressions
cat stupid.txt | sed -E 's/bla\{3,\}/BLA/g' # use -E and escape brackets

现在我不知道还有什么可以尝试的!

【问题讨论】:

    标签: bash sed bsd


    【解决方案1】:

    thing{3,} 匹配 thinggg。使用(..) 将事物分组以使量词适用于您想要的:

    $ echo blablabla | sed -E 's/(bla){3}/BLA/g'
    BLA
    

    【讨论】:

      【解决方案2】:

      如果啜饮整个文件是可以接受的:

      perl -0777pe 's/(\n){3,}/\n\n/g' newlines.txt
      

      您应该将\n 替换为合适的换行符。

      -0777 告诉 perl 不要将每一行分成自己的记录,这允许跨行工作的正则表达式起作用。

      如果您对结果满意,-i 会导致 perl 就地替换文件而不是输出到标准输出:

      perl -i -0777pe 's/(\n){3,}/\n\n/g' newlines.txt
      

      您也可以这样做:-i~ 创建具有给定后缀的备份文件(在本例中为~)。

      如果不能接受整个文件:

      perl -ne 'if (/^$/) {$i++}else{$i=0}print if $i<3' newlines.txt
      

      这将打印不是第三个(或更高)连续空行的任何行。 -i 与此相同。

      ps--MacOS 自带 perl 安装。

      【讨论】:

      • 我不确定“啜饮”在美味面条碗之外是什么意思……但它奏效了!为了只用 2 行替换许多空行,我按照您的建议替换了:perl -0777pe 's/(\n){3,}/\n\n\n/g'
      • :-) slurp其实意思是“一口气把整个文件吸进内存”,有点像面条。这可能是一种很棒的技术,就像这里一样,但有时不是处理大量文件的最佳方法,其中 “基于流” 方法更可取,例如 sed 编辑器。
      【解决方案3】:
      sed -E 's/bla{3,}/BLA/g' 
      

      以上匹配bl,后跟三个或更多重复的a。这不是你想要的。看来您实际上想要重复三个或更多 bla。如果是这样,那么替换:

      $ sed -E 's/bla{3,}/BLA/g' stupid.txt
      blablabla
      

      与:

      $ sed -E 's/(bla){3,}/BLA/g' stupid.txt
      BLA
      

      不过,上述内容并不能直接帮助您完成替换换行符的任务,因为默认情况下,sed 一次只读取一行。

      替换换行符

      让我们考虑这个在12 之间有3 个换行符的文件:

      $ cat file.txt
      
      1
      
      
      
      3
      

      用一个换行符替换任何出现的三个或更多换行符:

      $ sed -E 'H;1h;$!d;x; s/\n{3,}/\n/g' file.txt
      
      1
      3
      

      它是如何工作的:

      • H;1h;$!d;x

        这一系列复杂的命令读取整个文件。大概是 最简单的认为这是一个成语。如果你真的想知道 血淋淋的细节:

        • H - 追加当前行以保留空间
        • 1h - 如果这是第一行,则覆盖保留空间 有了它
        • $!d - 如果这不是最后一行,删除模式空间 并跳到下一行。
        • x - 交换保持和模式空间以放入整个文件 模式空间
      • s/\n{3,}/\n/g

        这会将三个或更多换行符的所有序列替换为单个换行符。

      备用

      上述解决方案一次读取整个文件。对于可能不利的大(千兆字节)文件。这种替代方法可以避免:

      $ sed -E '/^$/{:a; N; /\n$/ba; s/\n{3,}([^\n]*)/\1/}' file.txt # GNU only
      
      1
      3
      

      它是如何工作的:

      • /^$/{...}

        这会选择空行。对于空行和仅空行,执行大括号中的命令,它们是:

      • :a

        这定义了一个标签a

      • N

        这会将文件的下一行读入模式空间,与前一行用换行符分隔。

      • /\n$/ba

        如果读入的最后一行为空,则分支(跳转)到标签a

      • s/\n{3,}([^\n]*)/\1/

        如果我们没有分支,则执行此替换,删除多余的换行符。

      BSD 版本:我没有用于测试的 BSD 系统,但我猜:

      sed -E -e '/^$/{:a' -e N -e '/\n$/ba' -e 's/\n{3,}([^\n]*)/\1/}' file.txt
      

      【讨论】:

      • 只要输入文件没有空字符,就可以使用sed -z,而不是所有那些在换行时使用的sed命令。
      • @GeorgeVasiliou 对于 Linux 或其他使用 GNU sed 的任何人来说都是如此。不过,OP 说他在 Mac 上。
      • 当我运行您的第一个建议时,新行已正确识别,但奇怪的是它们被替换为“n”而不是实际的新行。所以你的例子的输出是1n3。这看起来很奇怪,因为它能够正确解释第一个 \n
      • 我也尝试了第二个“BSD 版本”的建议,但我得到了这个错误:sed: 1: "s/\n{3,}([^\n]*)/\1/}": bad flag in substitute command: '}' 所以也许有某种错字。但是,当我生成一个更大的文件时,它可能会在 linux 服务器上,所以 GNU 示例很受欢迎!
      【解决方案4】:

      要只保留 2 个换行符,你可以试试这个 sed

      sed '
        /^$/!b
        N
        /../b
        h
        :A
        y/\n/@/
        /^@$/!bB
        s/@//
        $bB
        N
        bA
        :B
        s/^@//
        /./ {
          x
          G
          b
        }
        g
      ' infile
      

      /^$/!b 如果是空行就不要打印了

      N 换行

      /../b 如果新行不为空,则打印 2 行

      h 在保持缓冲区中保留 2 个空行

      :一个标签A

      此时模式缓冲区中总是有2行,第一行是空的

      y/\n/@/ 用 @ 替换 \n(您可以选择文件中不存在的另一个字符)

      /^@$/!bB 如果第二行不为空跳转到B

      s/@// 去掉@

      $bB 如果是最后一行跳转到B

      此时模式空间中有1个空行

      N 获取最后一行

      bA 跳转到 A

      :B 标签B

      s/^@//去掉行首的@

      /./ {如果最后一行不为空

      x 交换模式和保持缓冲区

      G 将保持缓冲区添加到模式空间

      b 跳转到结尾

      }

      g 用保持空间替换模式空间(空)

      打印模式空间

      【讨论】:

      • 这主要是有效的,但由于某种原因,最后一行文本被删除了。我制作了一个比原始问题稍长的示例文件,该文件由多行文本组成,由可变数量的新行分隔。它有效,只是最后一行文本也被删除了。
      • @rrr 更新答案以保留最后一行,如果它不为空。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-01-29
      • 1970-01-01
      • 1970-01-01
      • 2016-05-18
      • 1970-01-01
      • 2015-03-08
      • 1970-01-01
      相关资源
      最近更新 更多