我希望我的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'时,也不会发生替换。
谢谢大家的帮助!
答案 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的设定方式也有点不清楚。您可能希望根据脚本的使用方式在该位置使用$ _。