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?


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ę).


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"

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


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' @

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

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'

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

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.


2

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

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


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/ {} +

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


-3

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


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,

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.