我正在尝试进行动态搜索,并在命令行中使用Perl替换,部分替换文本是反引号中grep命令的输出。这可以在命令行上执行,还是需要编写脚本来执行此操作?
这是我认为可以解决的命令。我认为Perl会将反引号视为命令替换,但它只是将反引号及其中的内容视为字符串:
perl -p -i -e 's/example.xml/http:\/\/exampleURL.net\/`grep -ril "example_needle" *`\/example\/path/g' `grep -ril "example_needle" *`
更新:
感谢您提供有用的答案。是的,我的原始单行中有一个拼写错误:grep的目标文件应该是*。
我根据Schewrn的例子编写了一个小脚本,但结果令人困惑。这是我写的脚本:
#!/usr/bin/env perl -p -i
my $URL_First = "http://examplesite.net/some/path/";
my $URL_Last = "/example/example.xml";
my @files = `grep -ril $URL_Last .`;
chomp @files;
foreach my $val (@files) {
@dir_names = split('/',$val);
if(@dir_names[1] ne $0) {
my $url = $URL_First . @dir_names[1] . $URL_Last;
open INPUT, "+<$val" or die $!;
seek INPUT,0,0;
while(<INPUT>) {
$_ =~ s{\Q$URL_Last}{$url}g;
print INPUT $_;
}
close INPUT;
}
}
基本上我要做的是:
运行我的脚本后,输入文件中的HTML代码完全乱码,它会切断文件中每行的前几个字符。这很奇怪,因为我确定$ URL_Last只在每个文件中出现一次,因此它应该只匹配一次并替换一次。这是否是由于滥用搜索功能造成的?
答案 0 :(得分:2)
您应该为s///
使用另一个分隔符,这样您就不需要在URL中转义斜杠:
perl -p -i -e '
s#example.xml#http://exampleURL.net/`grep -ril "example_needle"`/example/path#g'
`grep -ril "example_needle" *`
正则表达式中的grep
命令不会被执行,因为它只是一个字符串,反引号不是元字符。替换中的文本将充当双引号字符串中的内容。您需要/e
标志来执行shell命令:
perl -p -i -e '
s#example.xml#
qq(http://exampleURL.net/) . `grep -ril "example_needle"` . qq(/example/path)
#ge'
`grep -ril "example_needle" *`
但是,您对grep
命令的期望是什么?它缺少目标文件。 -l
将打印匹配文件的文件名,没有目标文件的grep
将使用stdin,我怀疑它不起作用。
如果是拼写错误,并且您打算使用与参数列表相同的grep,为什么不使用@ARGV
?
perl -p -i -e '
s#example.xml#http://exampleURL.net/@ARGV/example/path#g'
`grep -ril "example_needle" *`
这可能会也可能不会达到预期效果,具体取决于您是否希望在字符串中添加换行符。我不确定参数列表是否会被视为列表或字符串。
答案 1 :(得分:2)
看起来你要做的就是......
你有三个部分,你可以将它们组合成一个正则表达式,但通过三个步骤完成它会容易得多。当你需要添加它时,你不会在一周内讨厌自己。
第一步是获取文件名。
# grep -r needs a directory to search, even if it's just the current one
my @files = `grep -ril $search .`;
# strip the newlines off the filenames
chomp @files;
然后,如果您从grep
获得多个文件,则需要决定该怎么做。我会把这个选择留给你,我只想拿第一个。
my $file = $files[0];
然后构建URL。很容易......
# Put it in a variable so it can be configured
my $Site_URL = "http://www.example.com/";
my $url = $Site_URL . $file;
要做更复杂的事情,你可以使用URI。
现在搜索和替换是微不足道的。
# The \Q means meta-characters like . are ignored. Better than
# remembering to escape them all.
$whatever =~ s{\Qexample.xml}{$url}g;
您想使用-p
和-i
编辑文件。幸运的是,我们可以模仿该功能。
#!/usr/bin/env perl
use strict;
use warnings; # never do without these
my $Site_URL = "http://www.example.com/";
my $Search = "example-search";
my $To_Replace = "example.xml";
# Set $^I to edit files. With no argument, just show the output
# script.pl .bak # saves backup with ".bak" extension
$^I = shift;
my @files = `grep -ril $Search .`;
chomp @files;
my $file = $files[0];
my $url = $Site_URL . $file;
@ARGV = ($files[0]); # set the file up for editing
while (<>) {
s{\Q$To_Replace}{$url}g;
}
答案 2 :(得分:0)
每个人的回答都非常有助于我写一部为我工作的剧本。我实际上昨天发现了一个bash脚本解决方案,但是想发布一个Perl答案,以防其他人通过Google发现这个问题。
@TLP在http://codepad.org/BFpIwVtz发布的脚本是另一种方法。
以下是我最后写的内容:
#!/usr/bin/perl
use Tie::File;
my $URL_First = 'http://example.com/foo/bar/';
my $Search = 'path/example.xml';
my $URL_Last = '/path/example.xml';
# This grep returns a list of files containing "path/example.xml"
my @files = `grep -ril $Search .`;
chomp @files;
foreach my $File_To_Edit (@files) {
# The output of $File_To_Edit looks like this: "./some_path/index.html"
# I only need the "some_path" part, so I'm going to split up the output and only use @output[1] ("some_path")
@output = split('/',$File_To_Edit);
# "some_path" is the parent directory of "index.html", so I'll call this "$Parent_Dir"
my $Parent_Dir = @output[1];
# Make sure that we don't edit the contents of this script by checking that $Parent_Dir doesn't equal our script's file name.
if($Parent_Dir ne $0) {
# The $File_To_Edit is "./some_path/index.html"
tie @lines, 'Tie::File', $File_To_Edit or die "Can't read file: $!\n";
foreach(@lines) {
# Finally replace "path/example.xml" with "http://example.com/foo/bar/some_path/path/example.xml" in the $File_To_Edit
s{$Search}{$URL_First$Parent_Dir$URL_Last}g;
}
untie @lines;
}
}