2015-04-01 10 views
7

KorzystanieJak zastąpić ciąg w istniejącym pliku w Perl natomiast nie dotyka plików niezmienione

perl -pi -e 's/pattern/replacement/g' $(find src -type f) 

jest ładny, z wyjątkiem jednej rzeczy: Wszystkie pliki są nadpisywane, nawet tych bez meczu. To nie jest dobre, ponieważ często utrzymuję wiele z nich otwartych w Emacs lub Eclipse, które zadają mi nudne pytania. Czy istnieje prosty sposób, aby zapobiec dotykaniu niezmienionych plików (Coś takiego jak użycie polecenia grep w find to zbyt dużo pracy, szczególnie w przypadku złożonych wzorów).

Odpowiedz

4

Pierwsza rzecz, po otwarciu pliku, to unlink, co oznacza, że ​​nie można używać -i plików, których nie chcesz modyfikować.

find src -type f -exec grep -Pl 'pattern' {} + | 
    xargs perl -i -pe's/pattern/replacement/g' 

Oczywiście grep można już wykonać rekurencyjnych wyszukiwania, więc chyba trzeba użyć find dalej niż wskazane filtrowanie wyników, można użyć

grep -Plr 'pattern' src | 
    xargs perl -i -pe's/pattern/replacement/g' 

Uwaga: cmd | xargs perl ... puszka obsłużyć więcej plików niż perl ... $(cmd).

+0

Czy mógłbyś wyjaśnić swoją notatkę dotyczącą 'xargs'? – maaartinus

+0

@maaartinus, Istnieje ograniczenie wielkości linii poleceń. Jest znacznie większy niż kiedyś, ale nie jest tak trudno go dosięgnąć. 'xargs' rozwiązuje ten problem, uruchamiając program więcej niż raz, jeśli to konieczne. Na przykład, zrobi to 'foo plik1 plik2 ... plik499' i' foo plik500 plik501 ... plik999' zamiast tego robi 'foo plik1 plik2 ... plik999' jeśli to drugie nie jest możliwe. – ikegami

2

-p

powoduje Perl przyjąć następującą pętlę wokół swojego programu, co czyni go iteracyjne nad argumentów nazw plików trochę jak sed:

LINE: 
while (<>) { 
    ... # your program goes here 
} continue { 
    print or die "-p destination: $!\n"; 
} 

-i [rozszerzenie]

jest odpowiednikiem

#!/usr/bin/perl 
$extension = '.orig'; 
LINE: while (<>) { 
    if ($ARGV ne $oldargv) { 
     if ($extension !~ /\*/) { 
      $backup = $ARGV . $extension; 
     } 
     else { 
      ($backup = $extension) =~ s/\*/$ARGV/g; 
     } 
     rename($ARGV, $backup); 
     open(ARGVOUT, ">$ARGV"); 
     select(ARGVOUT); 
     $oldargv = $ARGV; 
    } 
    s/foo/bar/; 
} 
continue { 
    print; # this prints to original filename 
} 
select(STDOUT); 

Oznacza to, że możesz wziąć ten skrypt szkieletu i zmodyfikować przywracanie kopii zapasowej, jeśli nie dokonano żadnych zmian.

4

Zamiast przesyłać każdy plik do perla, który ma być przetworzony, wybierz je sam.

Znajdź pliki, które mają pattern w nich:

grep -Plr 'pattern' src 

Następnie użyj że zamiast tego find rozmowy:

perl -pi -e 's/pattern/replacement/g' $(grep -Plr pattern src) 

Albo jeszcze tak:

grep -Plr 'pattern' src | xargs perl -pi -e's/pattern/replacement/g' 

Będzie prawdopodobnie również będzie szybszy, ponieważ niepotrzebnie nie przetwarzasz plików.