2012-01-24 2 views
1

동적 검색을 수행하고 대체 텍스트의 일부가 백틱 내에서 grep 명령의 출력이되도록 명령 줄에서 Perl로 바꾸려고합니다. 명령 줄에서이 작업을 수행 할 수 있습니까? 아니면이 작업을 수행하는 스크립트를 작성해야합니까?Dynamic Perl은 백틱 내에서 grep을 사용하여 찾아서 바꿉니다.

여기 트릭을 수행 할 것으로 생각되는 명령이 있습니다. 펄이 명령 치환과 역 따옴표를 치료하는 것이라고 생각하지만, 대신 그냥 역 따옴표와 문자열로 그 안에 콘텐츠를 취급 :

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

을,'GREP은 표준 입력에 파일 이름을 인쇄 할 수있는 "example_needle"-ril', 대상 파일을 부족합니다. 아마도 당신은 단지 당신이 무엇을하려고 하는지를 설명하려고 노력해야합니다. – TLP

+0

시간을내어 질문으로 편집 할 수있는 작은 샘플 파일을 만들고 출력으로 필요한 것을 보여줍니다. 그렇지 않으면, 우리는 단지 짐작하고 있습니다. 행운을 빕니다. – shellter

+0

파일을 열 때 파일 핸들 위치가 이미 처음에 있으므로 찾기가 불필요합니다. 문제 설명에 관해서, 당신은 1 개의 예가 10 가지 이상의 에세이에 가치가 있다는 것을 알게 될 것입니다. 예를 들어'foo/bar.html'을 열고'/ example/example.xml'을'http : // examplesite.net/some/path/foo/example/example.xml'으로 바꾸고 싶다고 가정합니다. – TLP

답변

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; 
      } 
    } 
2

당신이 URL에 슬래시를 이스케이프 할 필요가 없습니다 있도록 s/// 또 다른 구분 기호를 사용해야합니다

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

그냥 문자열로 정규식 내부에 grep 명령이 실행되지 않습니다, 역 따옴표는 메타 문자가 아닙니다. 대용 암호 안에있는 텍스트는 마치 큰 따옴표로 묶인 문자열 안에있는 것처럼 작동합니다. 정확히 grep 명령이 어떤 작업을 수행 할 것으로 기대하고 무엇을, 그러나

perl -p -i -e ' 
s#example.xml# 
    qq(http://exampleURL.net/) . `grep -ril "example_needle"` . qq(/example/path) 
    #ge' 
    `grep -ril "example_needle" *` 

: 당신은 쉘 명령을 실행할 수있는 /e 플래그를 필요 했어? 대상 파일이 없습니다. -l은 일치하는 파일의 파일 이름을 출력하고 대상 파일이없는 grep은 stdin을 사용합니다. 나는 작동하지 않을 것으로 생각합니다.

오타이고 인수 목록과 동일한 grep을 사용하려는 경우 @ARGV을 사용하지 않으시겠습니까?

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

문자열에 줄 바꿈을 사용할 것으로 예상하는지 여부에 따라 예상 한대로 작동하지 않을 수도 있습니다. 인수 목록이 목록 또는 문자열로 간주 될지 확실하지 않습니다.

2

당신이하려는 것은 다음과 같습니다.

  1. 주어진 문자열이 포함 된 파일을 파일에서 찾습니다.
  2. 해당 파일을 사용하여 URL을 작성하십시오.
  3. 문자열의 내용을 해당 URL로 바꿉니다.

세 부분으로 나뉘어 하나의 정규식으로 묶을 수 있지만 3 단계로 수행하는 것이 훨씬 쉽습니다. 당신이 그것을 추가해야 할 주일에 당신 자신을 미워하지 않을 것입니다.

첫 번째 단계는 파일 이름을 얻는 것입니다.

# 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; 
} 
+0

shebang에서'-pi'를 사용하는 것이 좋습니다. 그러나이 경우에는 그렇게하지 않을 것입니다. 긴 버전을 사용한다면 타이핑을 저장하는 것이 중요하지 않습니다. 파일의 모든 행에 대해'grep'을 실행하여 성능을 저하시킵니다.이 경우 나는 대신에'while (<>)'과'print'를 추가하고,'$^I '를 설정하여 내부 편집을 수행한다. – TLP

+0

아, 아마도'$^I = shift; @ARGV, $ files [0];' – TLP

+0

@TLP 오, grep에 대한 좋은 점! 나는 당신이 원한다면 그것을 고칠 수 있도록 커뮤니티 위키 하나에 갈거야. – Schwern

관련 문제