Perl命令行多行替换

时间:2012-03-12 15:58:13

标签: linux perl ubuntu command-line

我正在尝试使用命令行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中为Perl尝试了Regex,它匹配了文本文件中的所有内容,但由于某种原因,它在命令行上使用perl无效。

我很感激一些帮助。

提前致谢。

2 个答案:

答案 0 :(得分:26)

您正在逐行阅读文件,因此只有第一行符合您的正则表达式。你想要做的事情 - 如果你真的想要删除大部分内容 - 是使用-0选项来诋毁文件,例如: -0777。这是行结束处理,777只是一个惯例用作八进制数的数字,足以导致文件淤塞。

perl -0777 -i -pe 's/(\[mysqld\][^\^]+)/$1\nsometext/g' test.txt

另外,我更换了你的报价。如果你在* nix,你似乎是,单引号是更好的。例如,$1不会被shell插入。

答案 1 :(得分:5)

-p switch使Perl迭代输入的每个并为每个执行给定的代码(并在之后打印行)。具体来说,命令

perl -p -e 'SOME_CODE_HERE;'

完全等同于运行以下Perl程序:

LINE: while (<>) {
    SOME_CODE_HERE;
} continue {
    print or die "-p destination: $!\n";
}

你的regexp似乎是要同时匹配多行,如果Perl逐行处理输入,这显然是行不通的。为了使其按预期工作,您有(至少)两个选项:

  1. 使用-0NNN switch更改Perl关于行的构成的概念。特别是,开关-0777使Perl将每个输入文件视为单个“行”。

  2. 将您的代码重写为例如使用.. flip-flop operator

  3. 顺便说一句,我强烈怀疑你的正则表达式并不意味着你的意思。特别是,[^\^]+匹配一个不包含插入符号(^)的一个或多个字符的字符串。由于您的输入似乎不太可能包含任何插入符号,因此如果您使用/s modifier,这似乎基本等同于(?s:.+)(或仅.+。)