sed:全局替换时忽略前导空格

rrf*_*eva 5 sed

我正在尝试编写一个 sed 命令来替换文件中过多的空格。每个单词之间应该只有一个空格,但前导空格和制表符应该单独留下。所以文件:

     This is     an indented      paragraph. The   indentation   should not be changed.
This is the     second   line  of the    paragraph. 
Run Code Online (Sandbox Code Playgroud)

会变成:

     This is an indented paragraph. The indentation should not be changed.
This is the second line of the paragraph.
Run Code Online (Sandbox Code Playgroud)

我尝试过

/^[ \t]*/!s/[ \t]+/ /g
Run Code Online (Sandbox Code Playgroud)

任何想法,将不胜感激。

Kus*_*nda 8

$ sed 's/\>[[:blank:]]\{1,\}/ /g' file
     This is an indented paragraph. The indentation should not be changed.
This is the second line of the paragraph.
Run Code Online (Sandbox Code Playgroud)

我使用的表达式匹配单词后的一个或多个[[:blank:]](空格或制表符),并将它们替换为单个空格。的一个字字符和非字字符之间的零宽度边界一致。\>

这是用 OpenBSD 的 native 测试过的sed,但我认为它也应该适用于 GNU sed。GNUsed\b用于匹配单词边界。

您也可以使用sed -E将其缩短为

sed -E 's/\>[[:blank:]]+/ /g' file
Run Code Online (Sandbox Code Playgroud)

同样,如果\>不适合你用GNU工作sed,使用\b来代替。


请注意,尽管上面以正确的方式整理了您的示例文本,但在标点符号后删除空格并不完全有效,如在第一个句子之后

sed -E 's/\>[[:blank:]]+/ /g' file
Run Code Online (Sandbox Code Playgroud)

为此,一个稍微复杂一点的变体可以解决这个问题:

     This is     an indented      paragraph.        The   indentation   should not be changed.
This is the     second   line  of the    paragraph.
Run Code Online (Sandbox Code Playgroud)

这将用非空白字符和单个空格替换后跟一个或多个空白字符的任何非空白字符。

或者,使用标准sed(以及一个非常小的优化,因为它只会在非空格/制表符后面有两个或更多空格/制表符时进行替换),

$ sed 's/\([^[:blank:]]\)[[:blank:]]\{2,\}/\1 /g' file
     This is an indented paragraph. The indentation should not be changed.
This is the second line of the paragraph.
Run Code Online (Sandbox Code Playgroud)


Sté*_*las 5

POSIXly:

sed 's/\([^[:space:]]\)[[:space:]]\{1,\}/\1 /g; s/[[:space:]]*$//'
Run Code Online (Sandbox Code Playgroud)

它用非空白和一个 SPC 字符替换非空白后面的一个或多个空白字符的任何序列,并删除尾随空白字符,这些空白字符将覆盖空白行和带有尾随空白的行(包括在来自 Microsoft 文本文件的行尾)。