Perl 命令行多行替换
Posted
技术标签:
【中文标题】Perl 命令行多行替换【英文标题】:Perl command line multi-line replace 【发布时间】:2012-03-29 01:13:00 【问题描述】:我正在尝试使用命令行 perl 替换多行文件中的文本。我正在使用 Ubuntu Natty。
以下是我的文本文件(称为 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
下面是我的 perl 命令:
perl -i -pe "s/(\[mysqld\][^\^]+)/\1\nsometext/g" test.txt
但是,我最终得到的不是替换文件中的所有文本,而是:
[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
#
我在 RegexBuddy for Perl 中尝试了 Regex,它匹配文本文件中的所有内容,但由于某种原因,它无法在命令行上使用 perl。
我将不胜感激。
提前致谢。
【问题讨论】:
我不确定预期的结果应该是什么。 @cornuz 我认为从问题中可以明显看出这一点。我说“不是替换文件中的所有文本,[以下]是我最终得到的......”所以这几乎解释了它。同样从正则表达式来看,我认为我需要什么结果似乎很清楚。 【参考方案1】:您正在逐行读取文件,因此只有第一行与您的正则表达式匹配。你想要做的——如果你真的想删除大部分内容——是通过使用-0
选项来删除文件,例如-0777
。这是行结束处理,777
只是一个按惯例用作八进制数的数字,大到足以导致文件乱码。
perl -0777 -i -pe 's/(\[mysqld\][^\^]+)/$1\nsometext/g' test.txt
另外,我替换了你的引号。如果你在 *nix 中,看起来你是,单引号是更可取的。例如,$1
不会被 shell 插值。
【讨论】:
非常感谢。我不得不将其修改为:perl -0777 -i -pe "s/(\[mysqld\][^\^]+)/\1\nsometext/g" test.txt
,因为稍后我将需要使用一些 shell 变量。干杯。
干杯。你知道我如何使用单引号包含 shell 变量吗?!在双引号中我做了这样的事情:perl -0777 -i -pe "s/(\[mysqld\][^\^]+)/\1\n$var/g" test.txt
,很高兴知道我如何使用单引号来实现同样的事情?!再次感谢。
@ChuckUgwuh 您可以在单行中插入 shell 变量,是的。但是如果你使用双引号,这意味着打算成为 perl 变量的变量也会被插值,所以会造成混淆。你为什么不试试看:perl -lwe "print $var"
谢谢。我会去做。看来双引号更适合我的具体情况,所以我现在会坚持下去,直到我弄清楚如何用单引号来做。干杯。
@ChuckUgwuh:通过命令行(一行)将变量传递到 Perl 的环境中:perlvar=$shellvar perl ... '...$ENV"$perlvar"...'
或者您可以将其导出(可能在单独的行上):export shellvar; perl ... '...$ENV"shellvar"...'
。前者使其仅可用于单个子进程(可能还有其子进程)的环境,而后者使其可用于任何子进程。【参考方案2】:
-p
switch 使 Perl 遍历输入的每一行 行 并为每一行执行给定的代码(然后打印这些行)。具体来说,命令
perl -p -e 'SOME_CODE_HERE;'
完全等同于运行以下 Perl 程序:
LINE: while (<>)
SOME_CODE_HERE;
continue
print or die "-p destination: $!\n";
您的正则表达式似乎旨在一次匹配多行,如果 Perl 逐行处理输入,这显然不起作用。要使其按预期工作,您有(至少)两种选择:
通过使用-0<i>NNN</i>
switch 改变 Perl 对什么构成行的概念。特别是,开关 -0777
使 Perl 将每个输入文件视为单个“行”。
将您的代码重写为例如使用..
flip-flop operator。
顺便说一句,我强烈怀疑您的正则表达式并不像您认为的那样。特别是,[^\^]+
匹配一个或多个不包含插入符号的字符串 (^
)。由于您的输入似乎不太可能包含任何插入符号,因此这似乎基本上等同于(?s:.+)
(或者如果您使用/s
modifier,则只是.+
)。
【讨论】:
以上是关于Perl 命令行多行替换的主要内容,如果未能解决你的问题,请参考以下文章