为什么在第2行和第3行的开头有一个美元符号?
➜ echo -e "hello\nworld" | perl -pe 's/$/\$/g'
hello$
$world$
$%
在上面,我试图在每一行的末尾添加一个美元符号,但不知何故它也在开头附加一个美元符号。启用全局标志时会执行此操作。但是当我删除全局标志时,它工作正常:
➜ echo -e "hello\nworld" | perl -pe 's/$/\$/'
hello$
world$
任何人都可以解释发生了什么吗?也许它与'\ r \ n'字符有关?
编辑:添加lookbehind案例
在这种情况下,这不仅仅是打破,还有其他情况。考虑以下:
➜ echo -e "A\nB\nC\nD" | perl -pe 's/(?<!A)$/\$/'
A
$B$
C$
D$
上面,我想用$来标记不以“A”结尾的行。第2行的额外美元符号不应该在那里。我甚至没有使用全球旗帜。
解决方案:现在好了。第二个解决方案是这样的(有关解释,请参阅Wiktor Stribiżew's answer)
➜ echo -e "A\nB\nC\nD" | perl -pe 's/(?<!A|\n)$/\$/'
A
B$
C$
D$
但要注意,如果你尝试使用多个单个字符,它会抛出Variable length lookbehind not implemented in regex
。例如:
➜ echo -e "AA\nBB\nCC\nDD" | perl -pe 's/(?<!AA|\n)$/\$/'
Variable length lookbehind not implemented in regex m/(?<!AA|\n)$/ at -e line 1.
要解决此问题,请在换行前添加适当数量的.
。
➜ echo -e "AA\nBB\nCC\nDD" | perl -pe 's/(?<!AA|.\n)$/\$/'
AA
BB$
CC$
DD$
关键是$
是零宽度断言,它可以在最终换行符之前匹配。 Perl读取一条尾随\n
的行,所以$
匹配两次:之前和之后。
你的字符串基本上是Perl的两行:
hello\n
world\n
并且$
可以在最终换行符之前和字符串的最后匹配。因此,两行中都有两个匹配(在此上下文中为“字符串”)。
如果要匹配字符串的结尾,请使用\z
:
perl -pe 's/\z/\$/g'
因为\z
只匹配字符串的最后一部分,但是不太可能有人想要使用它,因为它会在第二行和后续行的开头有效插入$
,并将其添加为最后一行。
要仅在最后一个$
之前插入\n
并停止,请使用你的perl -pe 's/$/\$/'
,没有g
修饰符。
如果您确实希望将其与全局替换一起使用,则可以使用以下命令:
echo -e "hello\nworld" | perl -pe 's/^(.*)$/\1\$/g'
hello$
world$
或者没有反向引用,您可以使用:
echo -e "hello\nworld" | perl -pe 's/\n$/\$\n/g'
hello$
world$
你可能需要用\n
替换\r\n
,如果你从windows操作文件或只是使用dos2unix
删除Windows EOL chars \r
。