Zastępowanie ciągów w plikach na podstawie określonych kryteriów wyszukiwania jest bardzo częstym zadaniem. Jak mogę
- zastąpić ciąg
foo
zebar
wszystkich plików w bieżącym katalogu? - zrobić to samo rekurencyjnie dla podkatalogów?
- zamieniać tylko, jeśli nazwa pliku pasuje do innego ciągu?
- zamieniać tylko, jeśli ciąg znajduje się w określonym kontekście?
- zastąpić, jeśli ciąg jest na określonym numerze linii?
- zamień wiele ciągów z tym samym zamiennikiem
- zamień wiele ciągów z różnymi zamiennikami
text-processing
awk
sed
perl
terdon
źródło
źródło
Odpowiedzi:
1. Zastępowanie wszystkich wystąpień jednego ciągu innym ciągiem we wszystkich plikach w bieżącym katalogu:
Są to przypadki, w których wiesz, że katalog zawiera tylko zwykłe pliki i że chcesz przetwarzać wszystkie pliki nie ukryte. Jeśli tak nie jest, zastosuj metody opisane w 2.
Wszystkie
sed
rozwiązania zawarte w tej odpowiedzi zakładają GNUsed
. W przypadku korzystania z FreeBSD lub OS / X, wymienić-i
się-i ''
. Należy również pamiętać, że użycie-i
przełącznika w dowolnej wersjised
ma pewne implikacje dla bezpieczeństwa systemu plików i jest niewskazane w żadnym skrypcie, który planuje się w jakikolwiek sposób rozpowszechniać.Nie rekurencyjne, tylko pliki w tym katalogu:
(
perl
jeden nie powiedzie się w przypadku nazw plików kończących się na|
spację ).Rekurencyjne, regularne pliki (w tym ukryte ) w tym i we wszystkich podkatalogach
Jeśli używasz zsh:
(może się nie powieść, jeśli lista jest zbyt duża, patrz
zargs
obejść).Bash nie może sprawdzić bezpośrednio zwykłych plików, potrzebna jest pętla (nawiasy klamrowe unikają globalnego ustawiania opcji):
Pliki są wybierane, gdy są rzeczywistymi plikami (-f) i można je zapisywać (-w).
2. Zastąp tylko, jeśli nazwa pliku pasuje do innego ciągu / ma określone rozszerzenie / jest określonego typu itp .:
Pliki nierekurencyjne tylko w tym katalogu:
Rekurencyjne, regularne pliki w tym i we wszystkich podkatalogach
Jeśli używasz bash (nawiasy klamrowe unikaj ustawiania opcji globalnie):
Jeśli używasz zsh:
Do
--
służy powiedziećsed
, że nie więcej flagi zostaną podane w wierszu poleceń. Jest to przydatne do ochrony przed nazwami plików rozpoczynającymi się od-
.Jeśli plik jest określonego typu, na przykład wykonywalny (zobacz
man find
więcej opcji):zsh
:3. Zastąp tylko, jeśli ciąg zostanie znaleziony w określonym kontekście
Wymień
foo
siębar
tylko wtedy, gdy znajduje siębaz
później na tej samej linii:Za
sed
pomocą\( \)
zapisuje wszystko, co jest w nawiasach, a następnie możesz uzyskać do niego dostęp za pomocą\1
. Istnieje wiele odmian tego tematu, aby dowiedzieć się więcej o takich wyrażeniach regularnych, zobacz tutaj .Wymienić
foo
zbar
tylko wtedy, gdyfoo
znajduje się na kolumnie 3d (pole) pliku (przy założeniu pola Oddzielona spacjami)(wymaga wersji
gawk
4.1.0 lub nowszej).W przypadku innego pola wystarczy użyć
$N
gdzieN
jest numerem pola zainteresowania. W przypadku innego separatora pól (:
w tym przykładzie) użyj:Inne rozwiązanie wykorzystujące
perl
:UWAGA: zarówno rozwiązania, jak
awk
iperl
wpłyną na odstępy w pliku (usuń początkowe i końcowe spacje oraz przekonwertuj sekwencje spacji na jeden znak spacji w pasujących liniach). Dla innego pola użyj$F[N-1]
gdzieN
jest żądany numer pola, a dla innego separatora pól ($"=":"
ustawia separator pól wyjściowych na:
):Wymień
foo
siębar
tylko na 4 linii:4. Wiele operacji zamiany: zamień na inne ciągi
Możesz łączyć
sed
polecenia:Pamiętaj, że zamówienie ma znaczenie (
sed 's/foo/bar/g; s/bar/baz/g'
zostanie zastąpionefoo
przezbaz
).lub Perl
Jeśli masz dużą liczbę wzorców, łatwiej jest zapisać wzorce i ich zamienniki w
sed
pliku skryptu:Lub, jeśli masz zbyt wiele par wzorów, aby powyższe było możliwe, możesz odczytać pary wzorów z pliku (dwa wzorce oddzielone spacjami, wzór $ i zastąpienie $, w wierszu):
To będzie dość powolne w przypadku długich list wzorców i dużych plików danych, więc możesz chcieć przeczytać wzorce i utworzyć
sed
z nich skrypt. Poniżej założono, że separator <space> oddziela listę par MATCH <space> REPLACE występujących jeden w wierszu w plikupatterns.txt
:Powyższy format jest w dużej mierze arbitralny i, na przykład, nie pozwala na użycie <spacji> w MATCH lub REPLACE . Metoda jest jednak bardzo ogólna: w zasadzie, jeśli możesz utworzyć strumień wyjściowy, który wygląda jak
sed
skrypt, możesz go pobrać jakosed
skrypt, określającsed
plik skryptu jako-
standard.Możesz łączyć i łączyć wiele skryptów w podobny sposób:
POSIX
sed
połączy wszystkie skrypty w jeden w kolejności, w jakiej pojawiają się w wierszu poleceń. Żadna z tych nie musi kończyć się\n
ewline.grep
może działać w ten sam sposób:Podczas pracy z ciągami stałymi jako wzorcami dobrą praktyką jest unikanie metaznaków wyrażeń regularnych . Możesz to zrobić dość łatwo:
5. Wiele operacji zamiany: zastąp wiele wzorców tym samym łańcuchem
Zastąpić dowolnego
foo
,bar
lubbaz
zfoobar
lub
źródło
zsh
. Jak najbardziej dodajzsh
informacje, ale nie ma powodu, aby usuwać bash. Wiem też, że używanie powłoki do przetwarzania tekstu nie jest idealne, ale są przypadki, w których jest to potrzebne. Zedytowałem w lepszej wersji mojego oryginalnego skryptu, który utworzysed
skrypt zamiast używać pętli powłoki do analizowania. Może to być przydatne, jeśli masz na przykład kilkaset par wzorów.(.)
kwalifikatora globbing, więc nie można go tutaj użyć. (również brakuje niektórych). Pętla for jest niepoprawna (brakuje -r) i oznacza wykonanie kilku przejść w plikach i nie daje żadnych korzyści w porównaniu ze skryptem sed.--
posed -i
i przed poleceniem zastępczym?-
. Korzystanie z niego gwarantuje, że polecenia będą działać na plikach o nazwach takich jak-foo
. Bez tego-f
byłoby analizowane jako opcja..git
katalogu i faktycznie popsują proces płatności. Lepiej operować w / w określonych katalogach według nazwy.Dobrym r e pl acement narzędzie Linux jest RPL , że dla projektu Debian został pierwotnie napisany, więc jest dostępna
apt-get install rpl
w każdej dystrybucji Debiana pochodzi, i może być dla innych, ale w przeciwnym razie można pobraćtar.gz
plik w SourgeForge .Najprostszy przykład użycia:
Zauważ, że jeśli ciąg zawiera spacje, powinien być ujęty w cudzysłów. Domyślnie
rpl
zajmuj się dużymi literami, ale nie pełnymi słowami , ale możesz zmienić te wartości domyślne za pomocą opcji-i
(ignoruj wielkość liter) i-w
(całe słowa). Możesz także określić wiele plików :Lub nawet określ rozszerzenia (
-x
) do przeszukiwania, a nawet przeszukuj rekurencyjnie (-R
) w katalogu:Możesz także wyszukiwać / zastępować w trybie interaktywnym za pomocą opcji
-p
(monit):Dane wyjściowe pokazują liczbę zastąpionych plików / ciągów i rodzaj wyszukiwania (wielkość liter / wrażliwe, całe / częściowe słowa), ale może być cichy z opcją
-q
( tryb cichy ) lub nawet bardziej szczegółowy, zawierając numery wierszy zawierające dopasowania każdego pliku i katalogu z opcją-v
( pełny tryb ).Inne opcje, które warto zapamiętać to
-e
(honor e scapes), które pozwalająregular expressions
, więc możesz przeszukiwać także tabulatory (\t
), nowe linie (\n
) itp. Nawet możesz użyć-f
do wymuszenia uprawnień (oczywiście tylko wtedy, gdy użytkownik ma uprawnienia do zapisu) i-d
do zachowania czasów modyfikacji`).Wreszcie, jeśli nie masz pewności, co dokładnie dokona, skorzystaj z
-s
( tryb symulacji ).źródło
Jak przeprowadzić wyszukiwanie i zastąpić wiele plików, sugeruje:
Moje najlepsze wyniki pochodzą z używania perla i grepa (aby upewnić się, że plik ma wyrażenie wyszukiwania)
źródło
Możesz używać Vima w trybie Ex:
źródło
Użyłem tego:
Wyświetl wszystkie pliki, które zawierają
old_string
.Zamień nowy wiersz w wyniku spacjami (tak, aby można było podać listę plików
sed
.Uruchom
sed
te pliki, aby zastąpić stary ciąg nowym.Aktualizacja: powyższy wynik nie powiedzie się w przypadku nazw plików zawierających białe spacje. Zamiast tego użyj:
grep --null -lr "old_string" | xargs --null sed -i 's/old_string/new_string/g'
źródło
grep --null -lr "old_string" | xargs --null sed -i 's/old_string/new_string/g'
sprawi, że poradzi sobie z dowolnymi nazwami plików.Z punktu widzenia użytkownika, ładne i proste narzędzie uniksowe, które doskonale wykonuje to zadanie
qsubst
. Na przykład,zastąpi
foo
siębar
we wszystkich moich plików C. Miłą cechą jest to, żeqsubst
zrobi query-replace , czyli pokaże mi każde wystąpieniefoo
i zapytać, czy chcę, aby zastąpić go lub nie. [Możesz bezwarunkowo zastąpić (bez pytania)-go
opcją, a istnieją inne opcje, np.-w
Jeśli chcesz zastąpićfoo
tylko całe słowo.]Jak go zdobyć:
qsubst
został wynaleziony przez der Mouse (z McGill) i opublikowany na stronie comp.unix.sources 11 (7) w sierpniu 1987 r. Istnieją zaktualizowane wersje. Na przykład wersja NetBSDqsubst.c,v 1.8 2004/11/01
kompiluje się i działa idealnie na moim komputerze Mac.źródło
Potrzebowałem czegoś, co zapewniłoby opcję uruchamiania na sucho i działałoby rekurencyjnie z glob, a po próbie zrobienia tego
awk
ised
poddałem się i zamiast tego zrobiłem to w pythonie.Skrypt przeszukuje rekurencyjnie wszystkie pliki pasujące do wzorca glob (np
--glob="*.html"
) przez regex i zastępuje z regex zastępczej:Każda długa opcja, taka jak
--search-regex
ma odpowiednią krótką opcję, tj-s
. Uruchom z,-h
aby zobaczyć wszystkie opcje.Na przykład spowoduje to odwrócenie wszystkich dat od
2017-12-31
do31-12-2017
:źródło
globstar
i**
globs lubfind
. Do suchego biegu wystarczy użyćsed
. O ile nie skorzystasz z tej-i
opcji, nie spowoduje to żadnych zmian. Do tworzenia kopii zapasowychsed -i.bak
(lubperl -i .bak
); w przypadku plików, które nie pasują, użyjgrep PATTERN file || echo file
. I dlaczego, u licha, miałbyś python rozwinąć glob zamiast pozwolić powłoce na to? Dlaczegoscript.py --glob=foo*
zamiast tylkoscript.py foo*
?sed
iawk
dobrze i nie chcąc poświęcać dodatkowego czasu na ich opanowanie, (4) czytelność, (5) to rozwiązanie będzie również działać na systemach nie posix (nie żebym tego potrzebował, ale mógłby ktoś inny).ripgrep (nazwa polecenia
rg
) jestgrep
narzędziem, ale obsługuje również wyszukiwanie i zamianę.rg
nie obsługuje opcji na miejscu, więc musisz to zrobić samZobacz dokumentację wyrażeń regularnych Rust, aby uzyskać składnię i funkcje wyrażeń regularnych.
-P
Przełącznik pozwoli PCRE2 smak.rg
domyślnie obsługuje Unicode.Podobnie
grep
,-F
opcja pozwoli na dopasowanie ustalonych ciągów, co jest przydatną opcją, którą moim zdaniemsed
powinienem również wdrożyć.Inną przydatną opcją jest
-U
dopasowanie wieloliniowerg
obsługuje także pliki w stylu dosKolejną zaletą
rg
jest to, że prawdopodobnie będzie szybszy niżsed
źródło