如何使用Perl更改目录(和子目录)中所有文件中出现的所有char

时间:2013-01-09 12:39:23

标签: perl awk replace

**我的后续问题标有' * *'**

我被要求编写Perl代码,用{替换每个{function(<counter>),并且在每次替换时,计数器应该大1。第一次替换{将为{function(0){的第二次替换将为{function(1)等。 它假设在包含子文件夹的文件夹中的每个*.c*.h文件中进行替换。

我写了这段代码:

#!/usr/bin/perl
use Tie::File;
use File::Find;
$counter = 0;
$flag = 1;

@directories_to_search = 'd:\testing perl';
@newString = '{ function('.$counter.')';
$refChar = "{";
finddepth(\&fileMode, @directories_to_search);


sub fileMode 
{
 my @files = <*[ch]>;   # get all files ending in .c or .h
 foreach $file (@files) # go through all the .c and .h flies in the directory  
{
    if (-f $file)  # check if it is a file or dir
    {
    my @lines;
# copy each line from the text file to the string @lines and add a function call after every     '{' '
    tie @lines, 'Tie::File', $file or die "Can't read file: $!\n";
    foreach ( @lines )
    {
        if (s/{/@newString/g)
        {
            $counter++;
            @newString = '{function('.$counter.')';
        }
        untie @lines; # free @lines
    }
    }
}   
}

代码搜索目录d:\testing Perl并进行替换,但不是获取 {function(<number>)我得到{function(number1) function(number3) function(number5) function(number7)例如我获得的第一次替换 {function(0) function(2) function(4) function(6)我希望获得{function(0)

我真的不知道我的代码有什么问题。

awk解决方案或任何其他Perl解决方案也将是伟大的!


* 我有一个跟进问题。 现在我希望我的perl程序在所有文件中进行相同的替换,除了行有'{'的行 和'}'在同一行。所以我用这种方式修改了代码。

#!/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
#foreach $filename (@ARGV) 
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";
    #$_='{function(' . $counter++ . ')';

    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();'

替换'{'

遗憾的是,此代码不起作用。 我很惭愧地说,我试图让它整天都工作,但仍然没有去。 我真的很感激一些帮助。

谢谢!!

4 个答案:

答案 0 :(得分:3)

这是将查找方法与就地编辑相结合的简单方法。您可以使用Tie::File,但它的结果确实相同。此外,不用说,在进行这样的编辑时,您应始终保留原始文件的备份,因为更改是不可逆转的。

因此,如果您不需要递归,那么您的任务在Unix / Linux风格中很简单:

perl -pi -we 's/{/"{ function(" . $i++ . ")"/ge' *.h *.c

当然,由于您似乎在使用Windows,cmd shell不会对我们的参数进行全局化,因此我们需要手动执行此操作。我们需要改变报价。而且,我们需要为-i(就地编辑)开关提供备份参数。

perl -pi.bak -we "BEGIN { @ARGV = map glob, @ARGV }; s/{/'{ function(' . $i++ . ')'/ge" *.h *.c

这几乎足以制作脚本。

如果确实需要递归,可以使用File::Find。请注意,此代码的功能与上面的代码完全相同。

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

my $dir = "d:/testing perl";   # 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;
    print;
}

不要被备份选项误导为错误的安全感:如果连续两次运行此脚本,那些备份将被覆盖,因此请记住这一点。

答案 1 :(得分:2)

$ perl -pi -e 's| (?<={) | q#function(# . ($i++) . q#)# |gex' *.c *.h

答案 2 :(得分:1)

使用awk '/{/{gsub(/{/,"{function("i++")");print;next}{print}'和您的代码作为输入:

$ awk '/{/{gsub(/{/,"{function("i++")");print;next}{print}' file
sub fileMode 
{function(0)
 my @files = <*[ch]>;   # get all files ending in .c or .h
 foreach $file (@files) # go through all the .c and .h flies in the directory  
{function(1)
    if (-f $file)  # check if it is a file or dir
    {function(2)
    my @lines;
# copy each line from the text file to the string @lines and add a function call after every     '{function(3)' '
    tie @lines, 'Tie::File', $file or die "Can't read file: $!\n";
    foreach ( @lines )
    {function(4)
        if (s/{function(5)/@newString/g)
        {function(6)
            $counter++;
            @newString = '{function(7)function('.$counter.')';
        }
        untie @lines; # free @lines
    }
    }
}   
}

注意:对于嵌入式嵌套{,函数编号不会递增。

$ echo -e '{ { \n{\n-\n{' | awk '/{/{gsub(/{/,"{function("i++")");print;next}1'
{function(0) {function(0) 
{function(1)
-
{function(2)

说明:

/{/                               # For any lines that contain {
gsub( /{/ , "{function("i++")" )  # replace { with function(i++)
print;next # print the line where the replacement happened and skip to the next
print                             # print all the lines 

答案 3 :(得分:1)

可以在一行中完成,如下所示:

perl -pi -e 's/({)/"{function(".++$a.")"/ge;' your_file

我刚刚采用了一个示例输入文件并进行了测试。

> cat temp
line-1 {    {    {   {
line-2 {    {   {
line-3 {    {
line-4 {

现在执行:

> perl -pi -e 's/({)/"{function(".++$a.")"/ge;' temp
> cat temp
line-1 {function(1)    {function(2)    {function(3)   {function(4)
line-2 {function(5)    {function(6)   {function(7)
line-3 {function(8)    {function(9)
line-4 {function(10)