2013-01-09 69 views
1

**我有一个标有“* *”的后续问题**如何更改目录使用Perl

我是在所有文件字符的所有出现(和子目录)要求编写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文件中找到我想要通过线走线和检查这一行是否包含“{”。如果是这样,程序将不检查是否有'{'并且不会进行替换,如果程序不会用'{'替换'{'();''

不幸的是,这段代码不起作用。 我很惭愧地说,我试图让它工作一整天,但仍然没有去。 我真的很感谢一些帮助。

谢谢!

+1

为什么要使用这两个文件::查找*和*一个水珠找到文件?你知道,这两次做同样的工作。 – TLP

+0

我没有看到你将字符串“数字”添加到代码中的任何东西。你确定你的意思是你在输出中看到“number1”,“number3”等吗? – TLP

回答

3

这是一个发现法就地编辑相结合的一个简单的事情。你可以使用Tie::File,但它最终的结果是一样的。不用说,在进行这样的编辑时,应始终保留原始文件的备份,因为更改是不可逆的。

所以,如果你不需要递归,你的任务是在Unix/Linux操作系统风格死的简单:

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

当然,因为你似乎是使用Windows,则cmd外壳不会我们glob的参数,所以我们需要手动完成。我们需要改变引号。而且,我们需要为-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; 
} 

不要哄骗到由备份选项安全的错觉:如果你连续两次运行此脚本,这些备份将被覆盖,所以记住这一点。

+0

卷曲不需要保存吗? – Zaid

+0

对,没有注意到。 – TLP

+0

这意味着什么保留下来? – MiSo

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 
+0

感谢您的快速响应。请你向我解释它是如何工作的。通过使用awk I ment系统调用。 – MiSo

+0

@MichaelSogolovsky我添加了一个解释。 –

+0

感谢您的快速回复。你能否向我解释它是如何工作的?这行代替了一个文件中的'{'而不是'文件'我需要指出文件的名称?或路径?再次谢谢! – MiSo

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

虽然这不适用于Windows。 – TLP

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) 
+0

除了使用'++'时不需要初始化'$ a',并且OP使用的是窗口,所以参数处理和就地编辑(您不使用)将不起作用。 – TLP

+0

更新了我的答案,删除了BEGIN块并添加了就地替换。 – Vijay