我想将文件中所有出现的\ntoken1\n
和更改\ntoken2\n
为token1
和。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
(如果您的令牌确实如此token1
,token2
您可以将正则表达式简化为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