如何使用 sed 删除字符串上方和下方的换行符?

如何使用 sed 删除字符串上方和下方的换行符?

我想将文件中所有出现的\ntoken1\n和更改\ntoken2\ntoken1和。token2

我以为这样就可以了:

${
N
N
s/\ntoken1\n/token1/
s/\ntoken2\n/token2/
}

但事实并非如此。

在此先感谢您的澄清。

答案1

您可以考虑使用非流式编辑编辑器提供了一个oin 命令并支持相对地址。例如给定

$ cat file
abc
def
token1
ghi
jkl
token2
mno
pqr

然后你可以G全局选择匹配的 token,然后oin 每个都有一个前一行和后一行:

$ printf '%s\n' 'g/token1\|token2/-1,+1j' ,p Q | ed -s file
abc
deftoken1ghi
jkltoken2mno
pqr

(如果您的令牌确实如此token1token2您可以将正则表达式简化为token[12])。

要在现场编辑,请将,p Q(打印然后无条件退出)替换为wq(写入并退出)。


如果必须使用 sed,那么一种方法是实现循环:

$ sed -E -e :a -e 'N;s/\n(token1|token2)\n/\1/' -e '/\n.*\n/!ba' -e 'P;D'  file
abc
deftoken1ghi
jkltoken2mno
pqr

这里/\n.*\n/!ba测试模式空间是否包含两个换行符(即三行长),如果不包含,则循环返回并添加另一行;否则P;D打印并删除一行循环返回。它们共同维护一个 3 行滑动窗口,用于应用替换。


注意:您没有提供测试用例,特别是您没有指出在 `\ntoken1\n` 和 `\ntoken2\n` 重叠的情况下所需的行为,例如应该
def
token1
ghi
token2

变得

deftoken1ghitoken2

或者

deftoken1ghi
token2

答案2

为了能够\n在命令中使用换行符,sed您必须使用-z标志,该标志用NUL字符而不是换行符 ( \n) 分隔行。因此,您可以使用以下命令:

sed -z 's/\ntoken1\n/token1/g;s/\ntoken2\n/token2/g' /path/to/file

其中/path/to/file是您要修改的文件的路径。

上述命令实际上不会将更改应用到您的文件。要应用更改,您可以将输出重定向到另一个文件,如下所示:

sed -z 's/\ntoken1\n/token1/g;s/\ntoken2\n/token2/g' /path/to/file > /path/to/another_file

或者,如果您希望将更改应用于同一个文件,请使用-i(就地)标志:

sed -z -i 's/\ntoken1\n/token1/g;s/\ntoken2\n/token2/g' /path/to/file

参考:

答案3

在 ERE 中,反斜杠用于转义(去除特殊含义)字符,以便与它们进行字面匹配...然而,在 BRE 中,它还为某些字符添加了特殊含义。

所以,它在两者中都有特殊含义,因此必须进行转义才能匹配为文字\

sed有一个--debug选项,您可以使用它来查看您的匹配项file

$ cat file
\ntoken1\n
\ntoken2\n

...使用你的 RegEx 模式\ntoken1\n\ntoken1\n如下所示:

$ sed --debug -e 's/\ntoken1\n/token1/' -e 's/\ntoken2\n/token2/' file
SED PROGRAM:
  s/\ntoken1\n/token1/
  s/\ntoken2\n/token2/
INPUT:   'file' line 1
PATTERN: \\ntoken1\\n
COMMAND: s/\ntoken1\n/token1/
PATTERN: \\ntoken1\\n
COMMAND: s/\ntoken2\n/token2/
PATTERN: \\ntoken1\\n
END-OF-CYCLE:
\ntoken1\n
INPUT:   'file' line 2
PATTERN: \\ntoken2\\n
COMMAND: s/\ntoken1\n/token1/
PATTERN: \\ntoken2\\n
COMMAND: s/\ntoken2\n/token2/
PATTERN: \\ntoken2\\n
END-OF-CYCLE:
\ntoken2\n

... 发现没有MATCHED REGEX报告。

如果你像这样逃避它:

$ sed --debug -e 's/\\ntoken1\\n/token1/' -e 's/\\ntoken2\\n/token2/' file
SED PROGRAM:
  s/\\\\ntoken1\\\\n/token1/
  s/\\\\ntoken2\\\\n/token2/
INPUT:   'file' line 1
PATTERN: \\ntoken1\\n
COMMAND: s/\\\\ntoken1\\\\n/token1/
MATCHED REGEX REGISTERS
  regex[0] = 0-10 '\ntoken1\n'
PATTERN: token1
COMMAND: s/\\\\ntoken2\\\\n/token2/
PATTERN: token1
END-OF-CYCLE:
token1
INPUT:   'file' line 2
PATTERN: \\ntoken2\\n
COMMAND: s/\\\\ntoken1\\\\n/token1/
PATTERN: \\ntoken2\\n
COMMAND: s/\\\\ntoken2\\\\n/token2/
MATCHED REGEX REGISTERS
  regex[0] = 0-10 '\ntoken2\n'
PATTERN: token2
END-OF-CYCLE:
token2

...然后,您得到一个MATCHED REGEX并且您的替换有效。

查找和替换所有事件,你需要设置G全局标志如下:

sed -e 's/\\ntoken1\\n/token1/g' -e 's/\\ntoken2\\n/token2/g' file

答案4

使用任何 awk 并且每次仅在内存中存储一​​行:

$ awk '
    /^(token1|token2)$/ { ors=ORS="" }
    { printf "%s%s", ors, $0; ors=ORS; ORS=RS }
    END { printf "%s", ors }
' file
abcdeftoken1ghi
jkltoken2mno
pqr

相关内容