与正则表达式模式并非如此,因为它是如何来实现它。我尝试过perl,sed和awk(各自尝试各种尝试),但我不确定这有多可能是一个单行(我更喜欢不编写perl脚本)。
说我有
#MARKER_TOP
INSERT INTO ('col1', 'col2', 'col3')
VALUES
(123,123,'2018-20-20 24:24:24',123)
...etc.
(123,123,'2018-20-20 24:24:24',123);
#MARKER_BOTTOM
...and more! (not all INSERT tables will be marked, btw)
我想要做的是用SQL NOW()
替换所有字符串日期。具体来说,使用Perl,我尝试了以下内容:
perl -w -pi.bak -e "undef $/; s/(#MARKER_TOP.*)'[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9] [0-9][0-9]:[0-9][0-9]:[0-9][0-9]'(.*#MARKER_BOTTOM)/$1 NOW() $2/msg" test.sql
但它正在完全剥离所有感兴趣的块(#MARKER_TOP
等)并用NOW()
替换它,这对于我想要的东西来说太过苛刻。
答案 0 :(得分:3)
一种简单的方法是使用range operator
use warnings;
use strict;
my $file = 'test.sql';
open my $fh, '<', $file or die "Can't open $file: $!";
my $re_date = qr/'\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}'/;
while (<$fh>)
{
if (/#MARKER_TOP/ .. /#MARKER_BOTTOM/) {
s/$re_date/NOW()/;
}
print;
}
或单行
perl -wpe"s/'\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}'/NOW()/
if /#MARKER_TOP/ .. /#MARKER_BOTTOM/
" test.sql
我用"..."
分隔代码,以便能够在内部使用'
(还有其他方法)。
我假设一行中有一个日期,严格按照问题中给出的格式在''
内。我通过添加另一个INSERT
部分进行测试,但没有标记。替换只发生在标记括号中。
范围运算符通过保持状态来工作:一旦其左操作数变为true,它就变为true,并且在右操作数变为true之前保持为真,之后在下一次迭代中返回false。它在标量上下文中以这种方式工作,而在列表上下文中,它返回该范围内的列表。请参阅链接的文档。
答案 1 :(得分:2)
您可以像这样使用awk
:
awk '/#MARKER_TOP/{m=1} /#MARKER_BOTTOM/{m=0} m{
gsub(/\047[0-9]{4}(-[0-9]{2}){2} [0-9]{2}(:[0-9]{2}){2}\047/, "NOW()")} 1' file
#MARKER_TOP
INSERT INTO ('col1', 'col2', 'col3')
VALUES
(123,123,NOW(),123)
...etc.
(123,123,NOW(),123);
#MARKER_BOTTOM
以下是它的工作原理:
/#MARKER_TOP/{m=1}
:当我们收到短信m=1
时设置标记#MARKER_TOP
/#MARKER_BOTTOM/{m=0}
:当我们收到短信m=0
#MARKER_BOTTOM
m{gsub(/.../, "NOW()")}
:m==1
时使用正则表达式将日期字符串替换为NOW()
1
:打印每条记录