逐行编辑到perl中文件夹(和子文件夹)中的所有文件

时间:2013-01-15 07:25:59

标签: perl replace

我希望我的perl程序替换'{' - > '{function('。counter ++。')'在除了同一行中有'{'和'}'的行之外的所有文件中,除非'{'在'typedef'下出现一行串。

#!/usr/bin/perl

use strict;
use warnings;
use Tie::File;
use File::Find;

my $dir = "C:/test dir";   


# fill up our argument list with file names:
find(sub { if (-f && /\.[hc]$/) { push @ARGV, $File::Find::name } }, $dir);

$^I = ".bak";   # supply backup string to enable in-place edit 

my $counter = 0; 

# now process our files 
while (<>) 
{
    my @lines;
    # copy each line from the text file to the string @lines and add a function call after every '{' '
    tie @lines, 'Tie::File', $ARGV or die "Can't read file: $!\n"

    foreach  (@lines) 
    {   
        if   (!( index (@lines,'}')!= -1 )) # if there is a '}' in the same line don't add the     macro
            {
                s/{/'{function(' . $counter++ . ')'/ge;
                print;
            }

    }
    untie @lines; # free @lines
}    

我想要做的是遍历我在我的目录和子目录中找到的@ARGV中的所有文件以及每个* .c或* .h文件我想逐行查看是否这行包含'{'。如果确实存在,程序将不会检查是否存在“{”并且不会进行替换,如果不存在,则程序将用'{function('。counter ++。')替换'{';'< / p>

遗憾的是,此代码不起作用。我很惭愧地说,我试图让它整天都工作但仍然没有。我认为我的问题是我不是在处理我搜索'{'的行,但我不明白为什么。我真的很感激一些帮助。

我还想补充一点,我在Windows环境中工作。

谢谢!!

编辑:到目前为止,在您的帮助下,这是代码:

use strict;
use warnings;
use File::Find;

my $dir = "C:/projects/SW/fw/phy";   # use forward slashes in paths

# fill up our argument list with file names:
find(sub { if (-f && /\.[hc]$/) { push @ARGV, $File::Find::name } }, $dir);

$^I = ".bak";   # supply backup string to enable in-place edit 

my $counter = 0; 

# now process our files
while (<>) {
    s/{/'{ function(' . $counter++ . ')'/ge unless /}/;
    print;
}

唯一剩下要做的就是当它在'typedef'子字符串下的一行时忽略'{'替换:

typedef struct 
{
}examp;

非常感谢您的帮助!谢谢! :)

编辑#2:这是最终代码:

use strict;
use warnings;
use File::Find;

my $dir = "C:/exmp";   

# fill up our argument list with file names:
find(sub { if (-f && /\.[hc]$/) { push @ARGV, $File::Find::name } }, $dir);

$^I = ".bak";   # supply backup string to enable in-place edit 

my $counter = 0; 
my $td = 0;

# now process our files
while (<>) {
    s/{/'{ function(' . $counter++ . ')'/ge if /{[^}]*$/ && $td == 0;
    $td = do { (/typedef/ ? 1 : 0 ) || ( (/=/ ? 1 : 0 ) && (/if/ ? 0 : 1 ) && (/while/ ? 0 : 1 ) &&             (/for/ ? 0 : 1 ) && (/switch/ ? 0 : 1 ) )}; 
    print;
}

代码执行替换,除非替换位置上方的行包含'typedef', 当它上面的行包括'='而没有'if','while','for'或'switch'时,也不会发生替换。

谢谢大家的帮助!

3 个答案:

答案 0 :(得分:3)

-i swith允许您预设备份文件的扩展名

使用perl:

perl -pe "/{[^}]*\$/&&do{s/{/{function('.counter++.');/}" -i.bak *

或(相同的结果):

perl -pe "s/{/{function('.counter++.');/ if /{[^}]*\$/" -i.bak *

为了处理子文件夹中的所有文件,使用find可能更简单:

find . -type f -print0 |
    xargs -0 perl -pe "s/{/{function('.counter++.');/ if /{[^}]*\$/" -i.bak

使用GNU sed可以让您快速完成工作

sed -e "/{[^}]*\$/{s/{/{function('.counter++.');/}" -i.bak *

修改仅在上一行包含字typedef 时进行修改

perl -pe "BEGIN { my \$td=1; };s/{/{function('.counter++.');/ if /{[^}]*\$/ && \$td==1 ; \$td=do{/typedef/?0:1};"  -i.bak *

可写;

perl -pe "
BEGIN { my \$td=0; };
s/{/{function('.counter++.');/ if /{[^}]*\$/ && \$td==0 ;
\$td=do{/typedef/?1:0};"  -i.bak *

或更具可读性

perl -pe '
    BEGIN { my $td=0; };
    s/{/{function(\047.counter++.\047);/ if /{[^}]*$/ && $td==0;
    $td=do{/typedef/?1:0};
  ' -i.bak *

或者作为perl脚本文件:cat >addFunction.pl

#!/usr/bin/perl -pi.bak
BEGIN { my $td = 0; }
s/{/{function(\047.counter++.\047);/ if /{[^}]*$/ && $td == 0;
$td = do { /typedef/ ? 1 : 0 };

说明:

  • BEGIN{...}命令块在程序开始时执行。
  • s/// if // &&替换如果当前匹配 $ td = 0
  • $td=do{ aaa ? bbb : ccc }向td致敬:如果是aaa那么bbb else ccc。

当perl运行时,$td保持他的价值直到下一次分配。因此,如果替换测试在$td分配之前进行,则检查将使用之前的值。

最后,使用sed:

sed -e '/{[^}]*$/{x;/./{x;s/{/{function(\o047.counter++.\o047);/;x;};x;};h;s/^.*typedef.*$//;x;' -i.bak *

或更具可读性:

sed -e '
    /{[^}]*$/{
        x;
        /./{
            x;
            s/{/{function(\o047.counter++.\o047);/;
            x;
        };
        x;
    };
    h;
    s/^/./;
    s/^.*typedef.*$//;
    x;
' -i.bak *

一些sed技巧:

  • h将当前行存储(备份)到保留空间
  • x保留空间交换当前工作线
  • s///众所周知的替换字符串命令
  • \o047 octal tick:'
  • /{[^}]*$/{ ... }命令块仅适用于加工{而非}的行。
  • /./{ ... }命令块仅在包含至少1个字符的行
  • 上执行

答案 1 :(得分:1)

如果存在'}',这是跳过替换的一种方法:

if ( $_ !~ /}/ ) {  # same as !( $_ =~ /}/ )

    s/{/'{function(' . $counter++ . ')'/ge;
}

确保print在条件之外,或者如果缺少'}',则不会打印该行。

其他写作方式:

unless ( /}/ ) {

    s/{/'{function(' . $counter++ . ')'/ge;
}

或者简单地说:

s/{/'{function(' . $counter++ . ')'/ge unless /}/;

答案 2 :(得分:0)

我认为这个问题是你在@lines中寻找索引。你想要这个:

while (<>) 
{
    my @lines;
    # copy each line from the text file to the string @lines and add a function call after every '{' '
    tie @lines, 'Tie::File', $ARGV or die "Can't read file: $!\n"

    foreach  my $line(@lines) 
    {   
        if   ( index ($lines,'}')== -1 ) # if there is a '}' in the same line don't add the     macro
            {
                $line =~ s/{/'{function(' . $counter++ . ')'/ge;
            }
        print $line;


    }
    untie @lines; # free @lines
}

我对ARGV的设定方式也有点不清楚。您可能希望根据脚本的使用方式在该位置使用$ _。