1

我正在尝试在命令行上进行动态搜索并替换为 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;
            }
    }

基本上我想做的是:

  1. 查找包含 $URL_Last 的文件。
  2. 将 $URL_Last 替换为 $URL_First 加上匹配文件所在目录的名称,再加上 $URL_Last。
  3. 将上述更改写入输入文件,而不修改输入文件中的任何其他内容。

运行我的脚本后,它完全混淆了输入文件中的 HTML 代码,并切断了文件中每一行的前几个字符。这很奇怪,因为我确定 $URL_Last 在每个文件中只出现一次,所以它应该只匹配一次并替换一次。这是由于滥用搜索功能引起的吗?

4

3 回答 3

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没有目标文件将使用标准输入,我怀疑这不起作用。

如果这是一个错字,并且您打算使用与参数列表相同的 grep,为什么不使用@ARGV?

perl -p -i -e '
s#example.xml#http://exampleURL.net/@ARGV/example/path#g'
    `grep -ril "example_needle" *`

这可能会或可能不会达到您的预期,具体取决于您是否希望在字符串中包含换行符。我不确定参数列表将被视为列表还是字符串。

于 2012-01-24T02:39:46.403 回答
2

看起来你想要做的是......

  1. 在包含给定字符串的树中查找文件。
  2. 使用该文件构建 URL。
  3. 用该 URL 替换字符串中的某些内容。

您有三个部分,您可以将它们组合成一个正则表达式,但分三步完成要容易得多。当你需要添加它时,你不会在一周内讨厌自己。

第一步是获取文件名。

# 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;
}
于 2012-01-24T03:29:05.973 回答
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;
            }
    }
于 2012-01-26T03:02:30.333 回答