匹配mac上sed中的重复字符

时间:2018-05-01 21:31:45

标签: bash sed bsd

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

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

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

创建一个名为stupid.txt的示例文件:

$ cat stupid.txt

blablabla
$

我的理解是您使用正则表达式语法thing{i,}匹配 i或更多内容
我尝试过这种变体来匹配3 bla没有运气:

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

现在我没有想过要尝试的其他方法!

4 个答案:

答案 0 :(得分:5)

thing{3,}匹配thinggg。使用(..)对事物进行分组,使量词适用于您想要的内容:

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

答案 1 :(得分:2)

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

答案 2 :(得分:2)

如果可以接受整个文件:

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

你应该用适当的换行符替换\n

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

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

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。

答案 3 :(得分:1)

要仅保留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行,第一行是空的

@ / n / @ /替换\ n由@(您可以选择文件中不存在的其他字符)

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

s / @ //删除@

$ bB如果最后一行跳到B

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

N得到最后一行

bA跳到A

:B标签B

s / ^ @ //删除行开头的@

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

x交换模式和保持缓冲区

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

b跳到最后

}

用保留空间

替换模式空间(空)

打印图案空间