Rekurencyjne wyszukiwanie i zastępowanie w plikach tekstowych na komputerach Mac i Linux

127

W powłoce Linuksa następujące polecenie będzie rekurencyjnie przeszukiwać i zamieniać wszystkie wystąpienia „to” na „tamto” (nie mam przed sobą powłoki Linuksa, ale powinno to zrobić).

find . -name "*.txt" -print | xargs sed -i 's/this/that/g'

Jak będzie wyglądać podobne polecenie w systemie OSX?

Jacek
źródło
Powinien prawdopodobnie przenieść się na, apple.stackexchange.componieważ nie jest wystarczająco ogólny dla Linuksa ani dla wszystkich programistów.
AlikElzin-kilaka,

Odpowiedzi:

246

OS X używa mieszanki narzędzi BSD i GNU, więc najlepiej zawsze sprawdzaj dokumentację (chociaż miałem ją, która lessnawet nie była zgodna ze stroną podręcznika OS X):

https://web.archive.org/web/20170808213955/https://developer.apple.com/legacy/library/documentation/Darwin/Reference/ManPages/man1/sed.1.html

sed przyjmuje argument after -ijako rozszerzenie dla kopii zapasowych. Podaj pusty ciąg ( -i '') bez kopii zapasowych.

Należy wykonać następujące czynności:

LC_ALL=C find . -type f -name '*.txt' -exec sed -i '' s/this/that/ {} +

To -type fpo prostu dobra praktyka; sed będzie narzekał, jeśli podasz mu katalog lub coś takiego. -execjest lepszy od xargs; nie musisz się tym przejmować -print0. Znak {} +na końcu oznacza, że finddoda wszystkie wyniki jako argumenty do jednego wystąpienia wywoływanego polecenia, zamiast ponownego uruchamiania go dla każdego wyniku. (Jedynym wyjątkiem jest sytuacja, gdy maksymalna liczba argumentów wiersza poleceń dozwolona przez system operacyjny zostanie naruszona; w takim przypadku finduruchomi więcej niż jedną instancję).

TaylanUB
źródło
2
Moje "this" w tym podstawieniu zawiera ukośnik (localhost / site) - zastępuję części adresu URL w pliku .html ... jak zrobić takie podstawienie. Próbowałem wstawić cudzysłowy, ale mi się to nie udaje.
Timothy T.
6
Składnia sed umożliwia zastosowanie niemal dowolny znak w miejscu kreską, np można użyć %znaku: sed "s%localhost/site%blah/blah%". Inną alternatywą jest interpretacja odwrotnego ukośnika-uniknąć segregatora sed "s/localhost\/site/blah\/blah/".
TaylanUB,
Dziękuję, pozwól mi spróbować. Próbowałem jednak użyć {} do oddzielenia ukośnika i nadal mam błąd ...
Timothy T.
16
Czy ktoś jeszcze ma illegal byte sequencebłąd? jeśli tak, spróbuj:, LC_ALL=C find . -type f -name '*.txt' -exec sed -i '' s/this/that/ {} +to zadziałało.
ColdTuna
10
Spowoduje to zastąpienie tylko jednej okurreny na plik, używanej /gw wielu przypadkach, takich jakLC_ALL=C find . -type f -exec sed -i '' s/search/replace/g {} +
jamesjara
152

W przypadku komputerów Mac bardziej podobne podejście byłoby następujące:

find . -name '*.txt' -print0 | xargs -0 sed -i "" "s/form/forms/g"
Guybrush Threepwood
źródło
10
Chciałbym móc głosować za tym za każdym razem, gdy do niego wracam i używam go. Byłoby już na +15, łatwe.
Droogans
Z jakiegoś powodu to nie działa dla mnie. To nic nie robi. Jestem w folderze form360 i próbuję zmienić wszystkie instancje ciągów o nazwie easyform na form360, uruchamiam następujące polecenie:find . -name '*.php' -print0 | xargs -0 sed -i "" "s/easyform/form360/g"
Andres Ramos
2
dla mnie to powinna być poprawna odpowiedź. To jedyny, który działał dla mnie.
nosequeldeebee
1
-print0 | xargs -0 nie działa na moim Macu, gdy nazwa pliku zawiera spację.
user2807219
1
sed:.: edycja
lokalna
14

Jako alternatywne rozwiązanie używam tego w systemie Mac OSX 10.7.5

grep -ilr 'old-word' * | xargs -I@ sed -i '' 's/old-word/new-word/g' @

Zasługa: odpowiedź Todd Cesere za

Maciej Gurban
źródło
Ten działa dobrze! Inne skrypty dodają dodatkowy koniec linii w niektórych przypadkach na OSX! Wielkie dzięki!
Sebastien Filion
14

W systemie Mac OSX 10.11.5 działa to dobrze:

grep -rli 'old-word' * | xargs -I@ sed -i '' 's/old-word/new-word/g' @
madx
źródło
xargs -I @ sed -i '' 's / stare-słowo / nowe-słowo / g' @ zadziałało dla mnie po wypróbowaniu wielu innych niedziałających sugestii. Dziękuję Ci!
DrB
13

Żadne z powyższych nie działa na OSX.

Wykonaj następujące czynności:

perl -pi -w -e 's/SEARCH_FOR/REPLACE_WITH/g;' *.txt
eb80
źródło
1
jak określić „/”, jeśli SEARCH_FOR i REPLACE_WITH są ścieżkami?
rraallvv
Użyj innego separatora. Jeśli używasz ścieżek, zadziała dwukropek lub kreska. 's | SEARCH | REPLACE | g', na przykład. Używamy nawiasów klamrowych, jak w 's {SEARCH} {REPLACE}'.
dannysauer,
1
dito pytanie, próbuję go nie na Macu - ale wydaje się, że generuje błąd? Na przykład moja ścieżka jest interpretowana jako plik? -bash: localhost / nohost: Nie ma takiego pliku lub katalogu
Timothy T.
to nie powtarza się w głębokich folderach. Tylko jeden poziom.
Sergey Romanov
Aby uzyskać więcej informacji na temat tego polecenia, przeczytaj to lifehacker.com/5810026/ ...
kuzdu
7

Wersja działająca zarówno w systemie Linux, jak i Mac OS X (po dodaniu -eprzełącznika do sed):

export LC_CTYPE=C LANG=C
find . -name '*.txt' -print0 | xargs -0 sed -i -e 's/this/that/g'
vroc
źródło
Musiałem zrobić eksport z tej odpowiedzi + wiersz z zaakceptowanej odpowiedzi (nie chciałem generować plików kopii zapasowej)
Lance
2
aby export LC_CTYPE=C && export LANG=C
usunąć
NIGDY NIE URUCHAMIAJ tego z '*' zamiast '* .filetype', tak jak to zrobiłem, jeśli używasz Git. Lub możesz pożegnać się z całą swoją niepublikowaną pracą.
Sergey
1
Wersja polecenia sed na mac wymaga znaku „” po znaku -i, więc ta odpowiedź jest niepoprawna
G Huxley
2

Za każdym razem, gdy wpisuję to polecenie, zawsze wydaje mi się, że go zawiązuję lub zapominam o fladze. Stworzyłem Gist na github na podstawie odpowiedzi TaylanUB, która zastępuje znalezisko globalne z bieżącego katalogu. Dotyczy to tylko systemu Mac OSX.

https://gist.github.com/nateflink/9056302

To miłe, ponieważ teraz po prostu otwieram terminal i kopiuję:

curl -s https://gist.github.com/nateflink/9056302/raw/findreplaceosx.sh | bash -s „find-a-url.com” „replace-a-url.com”

Możesz uzyskać dziwne błędy sekwencji bajtów, więc oto pełny kod:

#!/bin/bash
#By Nate Flink

#Invoke on the terminal like this
#curl -s https://gist.github.com/nateflink/9056302/raw/findreplaceosx.sh | bash -s "find-a-url.com" "replace-a-url.com"

if [ -z "$1" ] || [ -z "$2" ]; then
  echo "Usage: ./$0 [find string] [replace string]"
  exit 1
fi

FIND=$1
REPLACE=$2

#needed for byte sequence error in ascii to utf conversion on OSX
export LC_CTYPE=C;
export LANG=C;

#sed -i "" is needed by the osx version of sed (instead of sed -i)
find . -type f -exec sed -i "" "s|${FIND}|${REPLACE}|g" {} +
exit 0
Nate Flink
źródło
2

To jest mój wykonalny. w systemie Mac OS X 10.10.4

grep -e 'this' -rl . | xargs sed -i '' 's/this/that/g'

Powyższe użycie find zmieni pliki, które nie zawierają szukanego tekstu (doda nową linię na końcu pliku), czyli jest gadatliwy.

NoteCode
źródło
2

Jeśli używasz terminala zsh, możesz używać magii wieloznacznej:

sed -i "" "s/search/high-replace/g" *.txt

Mentor
źródło
1

Użyłem tego formatu - ale ... Okazało się, że musiałem uruchomić go trzy lub więcej razy, aby faktycznie zmienić każdą instancję, co wydało mi się wyjątkowo dziwne. Uruchomienie go raz zmieniłoby niektóre w każdym pliku, ale nie wszystkie. Uruchomienie dokładnie tego samego ciągu dwa-cztery razy spowoduje przechwycenie wszystkich instancji.

find . -type f -name '*.txt' -exec sed -i '' s/thistext/newtext/ {} +
Emma
źródło
Musiałeś uruchomić to polecenie wiele razy b / c twoje wyrażenie regularne sed wymaga gna końcu, w przeciwnym razie zastępuje tylko pierwsze wystąpienie thistextw linii. Więc twoje wyrażenie regularne powinno wyglądać taks/thistext/newtext/g
Les Nightingill
0

https://bitbucket.org/masonicboom/serp to narzędzie go (tj. wieloplatformowe), przetestowane na OSX, które wykonuje cykliczne przeszukiwanie i zastępowanie tekstu w plikach w danym katalogu i potwierdza każdą zamianę. Jest nowy, więc może być wadliwy.

Sposób użycia wygląda następująco:

$ ls test
a  d  d2 z
$ cat test/z
hi
$ ./serp --root test --search hi --replace bye --pattern "*"                         
test/z: replace hi with bye? (y/[n]) y
$ cat test/z
bye
user4425237
źródło
0
find . -type f | xargs sed -i '' 's/string1/string2/g'

Więcej informacji znajdziesz tutaj .

user2725109
źródło
-3

Polecenie na OSX powinno być dokładnie takie samo, jak w systemie Unix pod ładnym interfejsem użytkownika.

clops
źródło
Myślałem o tym, ale nie. Umieszcza ./ przed plikami podczas przesyłania do seda, więc sed skarży się na „nieprawidłowy kod polecenia”. Może jestem po prostu zmęczony ;-)
Jack
@JacobusR, wytnij i wklej z terminala OSX - musisz wprowadzać coś nieco innego.
glenn jackman
3
Możesz chcieć -print0dodać do findflag i -0do xargsflag.
jmtd
Możesz też po prostu użyć -exec sed -i s/this/that/g {} \+zamiast -printi xargs
Marian
@JacobusR - to działa, nawet jeśli istnieje początkowa ścieżka „./”. Jeśli jednak w nazwie pliku jest spacja, powiedz „./jacobus \ R.txt”, użycie xargsmoże spowodować wyświetlenie rozdzielanego spacjami „./jacobus” jako pliku do przekazania sed, a następnie „R.txt” , z których żaden nie istnieje.
Brett Hale,
-4

można po prostu powiedzieć $ PWD zamiast „.”

Samuel Devlin
źródło