2013-05-01 62 views
1

我很确定我正在做一些愚蠢的事情,我提前道歉。我曾看过其他人在类似搜索中提出的单行,我喜欢他们的想法,但我不确定如何申请,因为它不是直接交换。如果答案是不能做到的话,那很好,我会为此编写脚本。如何在文件内使用perl和regex/sed更改值?

问题:我有需要通过解析器发送的日志文件,需要日期为YYYY-MM-DD。这些文件可以这样保存;然而,有些人更喜欢他们在YYYY/MM/DD为他们自己的观看,并发送给我。我可以用sed修改一个或两个日期,并且这个工作很好。然而,当文件中有2-3年以上时,不必为每个日期手动完成。

我的代码(我留在原地调试命令):

use strict; 

use File::Copy; 
use Getopt::Std; 

my %ARGS =(); 
getopts('f:v', \%ARGS); 

my $file = $ARGS{f}; 

&main(); 

sub main($) 
{ 
    open (FIN, "<$file") || die ("Cannot open file"); 
    print "you opened the file\n"; 
while (<FIN>) { 
    my $line = $_; 
    if ($line =~ /(\d*)\/(\d*)\/(\d*) /i) { 
     #print "you are in the if"; 
     my $year = $1; 
     my $month = $2; 
     my $day = $3; 

     print $line; 
     print "\nyou have year $1\n"; 
     print "you have month $2\n"; 
     print "you have day $3\n"; 

     s/'($1\/$2\/$3)/$1-$2-$3'/; 

    } 
} 

close FIN; 
} 

我可以看到,正则表达式是获得正确的价值观为我的变量,但原来的线没有在文件中被替换。

问题:

1)如果这是可以在同一个文件中做或我需要它输出到不同的文件?看其他答案,相同的文件应该没问题。 2)是否需要以另一种方式打开文件或以某种方式设置为写入文件,而不是像运行sed一样运行replace命令?我担心失败可能会在这个简单的地方,我可以忽略不计。

谢谢!

+2

你在哪里写入文件...? – ikegami 2013-05-01 18:31:52

+2

不建议写入您正在阅读的同一个文件。你可以做的是写入一个临时文件,然后将该文件复制到原始文件中。你也可以用'-i'标志来尝试使用'sed',这会在原地修改文件。 – 2013-05-01 18:40:42

+0

谢谢你们俩的反馈。这证实了我在想什么。我还没有想出如何使它与多个日期的sed工作。 – user438596 2013-05-02 04:38:39

回答

1
perl -pi.bak -e 's|(\d{4})/(\d\d)/(\d\d)|$1-$2-$3|g;' input 

与日志文件名称替换输入。备份文件input.bak将在您需要原始数据的情况下创建。

+0

谢谢!那样做了。我可以问一下使用'|'吗?而不是在你的'''之后'和'g'之前的'/'?这是一种风格偏好还是会修改脚本的行为方式? – user438596 2013-05-02 04:41:05

+0

理论上这应该可以作为shell脚本,别名或它自己独特的.pl文件放在一起,这样我可以更简单地调用这个一行代码? – user438596 2013-05-02 05:23:22

+0

'|'允许在正则表达式中使用/而不需要在它之前放置反斜杠\。特殊的标志使它更好地作为一个单线程而不是写一个.pl文件,但你绝对可以在shell脚本中使用相同的单线程。 – 2013-05-02 16:52:54

3

你永远不会写入文件。使用sed,你会使用-i,并且你可以在Perl中完全相同。

perl -i -pe's{(\d{4})/(\d{2})/(\d{2})}{$1-$2-$3}g' file 

或者用备份:

perl -i~ -pe's{(\d{4})/(\d{2})/(\d{2})}{$1-$2-$3}g' file 

这相当于

local $^I = ''; # Or for the second: local $^I = '~'; 
while (<>) { 
    s{(\d{4})/(\d{2})/(\d{2})}{$1-$2-$3}g; 
    print; 
} 

如果你不想靠$^I,你必须复制它的行为。

for my $qfn (@ARGV) { 
    open($fh_in, '<', $qfn) 
     or do { warn("Can't open $ARGV: $!\n"); next; }; 

    unlink($qfn) 
     or do { warn("Can't overwrite $ARGV: $!\n"); next; }; 

    open(my $fh_out, '>', $qfn) { 
     or do { warn("Can't create $ARGV: $!\n"); next; }; 

    while (<$fh_in>) { 
     s{(\d{4})/(\d{2})/(\d{2})}{$1-$2-$3}g; 
     print $fh_out $_; 
    } 
} 
+0

删除了不正确的'/ e'。 – ikegami 2013-05-01 20:29:30

+0

甜美;感谢您提供关于如何做到这一点的信息。 – user438596 2013-05-02 14:33:42