Linux Perl 命令行多行替换
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/9670426/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Perl command line multi-line replace
提问by Obinwanne Hill
I'm trying to replace text in a multi-line file using command-line perl. I'm using Ubuntu Natty.
我正在尝试使用命令行 perl 替换多行文件中的文本。我正在使用 Ubuntu Natty。
Below is the content of my text file (called test.txt):
下面是我的文本文件(称为 test.txt)的内容:
[mysqld]
#
# * Basic Settings
#
#
# * IMPORTANT
# If you make changes to these settings and your system uses apparmor, you may
# also need to also adjust /etc/apparmor.d/usr.sbin.mysqld.
#
user = mysql
socket = /var/run/mysqld/mysqld.sock
port = 3306
basedir = /usr
datadir = /var/lib/mysql
tmpdir = /tmp
skip-external-locking
Below is my perl command:
下面是我的 perl 命令:
perl -i -pe "s/(\[mysqld\][^\^]+)/\nsometext/g" test.txt
However, instead of replacing all the text in the file, below is what I end up with:
但是,不是替换文件中的所有文本,而是我最终得到的内容:
[mysqld]
sometext#
# * Basic Settings
#
#
# * IMPORTANT
# If you make changes to these settings and your system uses apparmor, you may
# also need to also adjust /etc/apparmor.d/usr.sbin.mysqld.
#
user = mysql
socket = /var/run/mysqld/mysqld.sock
port = 3306
basedir = /usr
datadir = /var/lib/mysql
tmpdir = /tmp
skip-external-locking
#
I tried the Regex in RegexBuddy for Perl and it matches everything in the text file, but for some reason it's not working using perl on the command line.
我在 RegexBuddy 中为 Perl 尝试了 Regex,它匹配文本文件中的所有内容,但由于某种原因,它无法在命令行上使用 perl。
I'd appreciate some assistance.
我很感激一些帮助。
Thanks in advance.
提前致谢。
采纳答案by TLP
You are reading the file line-by-line, so only the first line matches your regex. What you'll want to do -- if you truly wish to delete most of the content -- is to slurp the file by using the -0
option, e.g. -0777
. This is line ending processing, and 777
is just a number used by convention as an octal number large enough so as to cause file slurping.
您正在逐行阅读文件,因此只有第一行与您的正则表达式匹配。你想要做的——如果你真的想删除大部分内容——是通过使用-0
选项来啜饮文件,例如-0777
. 这是行结束处理,777
只是一个按照惯例使用的数字,作为一个足够大的八进制数,以导致文件啜饮。
perl -0777 -i -pe 's/(\[mysqld\][^\^]+)/\nsometext/g' test.txt
Also, I replaced your quotes. If you are in *nix, which it seems you are, single quotes are preferable. Case in point, $1
would not be interpolated by the shell.
另外,我替换了您的报价。如果你在 *nix 中,看起来你是,单引号更可取。举个例子,$1
shell 不会插入。
回答by Ilmari Karonen
The -p
switchcauses Perl to iterate over every lineof the input and execute the given code for each of them (and to print the lines afterwards). Specifically, the command
该-p
开关使 Perl 遍历输入的每一行并为每行执行给定的代码(并在之后打印这些行)。具体来说,命令
perl -p -e 'SOME_CODE_HERE;'
is exactly equivalent to running the following Perl program:
完全等同于运行以下 Perl 程序:
LINE: while (<>) {
SOME_CODE_HERE;
} continue {
print or die "-p destination: $!\n";
}
Your regexp seems to be intended to match multiple lines at once, which obviously won't work if Perl is processing the input line by line. To make it work as intended, you have (at least) two options:
您的正则表达式似乎旨在一次匹配多行,如果 Perl 逐行处理输入,这显然不起作用。要使其按预期工作,您(至少)有两个选择:
Change Perl's notion of what constitutes a line by using the
-0NNN
switch. In particular, the switch-0777
causes Perl to treat every input file as a single "line".Rewrite your code to e.g. use the
..
flip-flop operator.
By the way, I strongly suspect that your regexp doesn't mean what you think it means. In particular, [^\^]+
matches a string of one or more characters that doesn't contain a caret (^
). Since your input doesn't seem likely to contain any carets, this seems essentially equivalent to (?s:.+)
(or just .+
if you use the /s
modifier).
顺便说一句,我强烈怀疑您的正则表达式并不意味着您认为它意味着什么。特别是,[^\^]+
匹配不包含脱字符 ( ^
)的一个或多个字符的字符串。由于您的输入似乎不太可能包含任何插入符号,因此这似乎本质上等同于(?s:.+)
(或仅.+
当您使用/s
修饰符时)。