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 は各ファイルで 1 回しか発生しないことがわかっているため、これは奇妙です。これはシーク機能の誤用によるものでしょうか?

4

3 に答える 3

2

あなたがやろうとしていることのようです...

  1. 指定された文字列を含むツリー内のファイルを検索します。
  2. そのファイルを使用して URL を作成します。
  3. 文字列内の何かをその URL に置き換えます。

3 つの部分があり、それらを 1 つの正規表現にまとめることができますが、3 つのステップで行う方がはるかに簡単です。追加する必要がある場合、1週間で自分を嫌いになることはありません。

最初のステップは、ファイル名を取得することです。

# 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。その選択はあなたに任せます。私は最初の 1 つを選択します。

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 に答える
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シェル コマンドを実行するには、フラグが必要です。

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" *`

これは、文字列に改行があると予想されるかどうかに応じて、期待どおりになる場合とそうでない場合があります。引数リストがリストまたは文字列と見なされるかどうかはわかりません。

于 2012-01-24T02:39:46.403 に答える
0

みんなの答えは、私のために働くことになったスクリプトを書くのに非常に役立ちました. 昨日、実際に bash スクリプト ソリューションを見つけましたが、他の誰かが Google でこの質問を見つけた場合に備えて、Perl の回答を投稿したいと思いました。

@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 に答える