linux
  • bash
  • recursion
  • sed
  • grep
  • 2013-04-10 10 views 28 likes 
    28

    DostajęZnajdź i zamień ciąg w wszystkich plików za pomocą rekurencyjnych grep i sed

    sed: -e expression #1, char 22: unterminated `s' command 
    

    jest jakiś problem na moim skrypcie? Również "oldstring" zawiera znaki specjalne

    #!bin/bash 
    oldstring='<script>"[oldscript]"</script>' 
    newstring='<script>"[newscript]"</script>' 
    grep -rl $oldstring /path/to/folder | xargs sed -i s/$oldstring/$newstring/g 
    
    +1

    Nawiasy kwadratowe konieczne może być uciekł. Podwójnie cytuj wzór sed. – phs

    +3

    Będziesz także mieć problem z '/' we wzorcach. Powinni być uciekani. Lub możesz użyć innego separatora dla polecenia 's' (np.' @ '). –

    Odpowiedz

    36

    Jak powiedział @Didier można zmienić separator do czegoś innego niż /:

    grep -rl $oldstring /path/to/folder | xargs sed -i [email protected][email protected][email protected] 
    
    +5

    Powyższe może zawieść na tyle interesujących sposobów, biorąc pod uwagę tak wiele możliwych treści tricolor lub newstring. –

    +1

    @EdMorton, czy mógłbyś podać przykład tego, jak to się nie udaje? Wiem, że opublikowaliście tradycyjną formę robienia tego poniżej, ale tylko stwierdzenie, że może zawieść, pozostawia pytanie o to, jak. Wtedy mogłem zrozumieć, dlaczego powinienem rozwiązać twoje rozwiązanie. Takie rozwiązanie wydaje się o wiele łatwiejsze. Dzięki –

    +3

    Wypróbuj powyższe za pomocą dowolnego znaku globu powłoki lub zmiennej @ w dowolnej zmiennej łańcuchowej. Znaki globujące mogą/będą pasować do nazw plików w twoim katalogu, jeśli nie dzisiaj, to pewnego dnia w przyszłości, kiedy będziesz go oczekiwał, a @ zakończy działanie polecenia sed. To również się nie powiedzie, jeśli oldstring zawiera spacje w różnych lokalizacjach, nie mówiąc o tym, czy któryś z nich zawiera znaki nowej linii. OP dokładnie powiedział, że "ten" staroświecki "ma specjalne postacie", więc jest to duża wzmianka, że ​​jakiekolwiek z tego, co właśnie opisałem, i więcej, może się wydarzyć. –

    3

    sed wyrażenie musi być cytowany

    sed -i "s/$oldstring/$newstring/g" 
    
    4

    Faceci GNU NAPRAWDĘ zawiedli, gdy wprowadzili rekursywne wyszukiwanie plików na grep. grep służy do wyszukiwania RE w plikach i drukowania pasującej linii (g/re/p pamiętasz?) NIE dla wyszukiwania plików. Jest bardzo dobre narzędzie o bardzo oczywistej nazwie do wyszukiwania plików. Cokolwiek stało się z mantrą UNIXa, zrobić jedną rzecz i zrobić to dobrze?

    W każdym razie, oto jak chcesz robić to, co chcesz przy użyciu tradycyjnego podejścia UNIX (niesprawdzone):

    find /path/to/folder -type f -print | 
    while IFS= read -r file 
    do 
        awk -v old="$oldstring" -v new="$newstring" ' 
         BEGIN{ rlength = length(old) } 
         rstart = index($0,old) { $0 = substr($0,rstart-1) new substr($0,rstart+rlength) } 
         { print } 
        ' "$file" > tmp && 
        mv tmp "$file" 
    done 
    

    Nie dlatego, że za pomocą awk/index() zamiast sed i grep Ci uniknąć konieczności uciec wszystkie metaznaki RE, które mogą pojawić się w starym lub nowym łańcuchu, i wymyślić znak, który będzie użyty jako ogranicznik sed, który nie może pojawić się w starych lub nowych ciągach, i że nie musisz uruchamiać grep ponieważ zastąpienie nastąpi tylko w przypadku plików, które zawierają żądany ciąg znaków. Powiedziawszy to wszystko, jeśli nie chcesz, aby znacznik czasu pliku się zmieniał, jeśli nie modyfikujesz pliku, po prostu zrób różnicę w tmp i oryginalnym pliku przed wykonaniem mv lub wrzuć fgrep -q przed awk.

    Zastrzeżenie: Powyższe nie działa w przypadku nazw plików zawierających znaki nowej linii. Jeśli masz te, daj nam znać, a my pokażemy Ci, jak sobie z nimi radzić.

    +2

    +1 Gdy ktoś mówi o używaniu 'sed' z' grep', istnieje doskonała szansa, że ​​powinni używać 'sed' lub przełączać się na' awk'. Nawiasem mówiąc, jeśli użyłeś '-print0' w twoim znalezisku, i (w BASH) używając' -d \ 0' powinieneś zadbać o nazwy plików z nowymi liniami w nich. –

    +0

    @DavidW. Dobrze.A kiedy zaczniesz mówić o ucieczce metaznaków RE, tak aby sed lub grep nie traktował ich jako takich, musisz przełączyć się na awk/index() lub fgrep, abyś mógł szukać ciągów zamiast RE. –

    +0

    @josten Argument '-r' dla' grep' jest alternatywą dla użycia 'find', aby nie używać' awk'. Możesz użyć 'awk' z' find + xargs' zamiast 'grep + sed', a wynik będzie zazwyczaj bardziej zwięzły i efektywny. Użycie 'awk' z pewnością nie spowoduje, że utworzysz ogromne zawiłe jednolinijki. –

    9
    grep -rl $oldstring . | xargs sed -i "s/$oldstring/$newstring/g" 
    
    +0

    Tak więc komplikacja z tym, że pliki ze spacjami w swoich nazwach nie zostaną zebrane. Gdybyś miał "/ files/File Two.txt", sed wypróbowałby "/ files/File" i "Two.txt". – Captainlonate

    -1
    grep -rl SOSTITUTETHIS . | xargs sed -Ei 's/(.*)SOSTITUTETHIS(.*)/\1WITHTHIS\2/g' 
    
    Powiązane problemy