Znajdź i zamień tekst w pliku za pomocą poleceń


Odpowiedzi:


1053
sed -i 's/original/new/g' file.txt

Wyjaśnienie:

  • sed = Edytor strumienia
  • -i = w miejscu (tj. zapisz z powrotem do oryginalnego pliku)
  • Ciąg poleceń:

    • s = polecenie zastępcze
    • original = wyrażenie regularne opisujące słowo do zastąpienia (lub tylko samo słowo)
    • new = tekst, który ma go zastąpić
    • g = globalny (tzn. zastąp wszystkie, a nie tylko pierwsze wystąpienie)
  • file.txt = nazwa pliku


3
@Akiva Jeśli uwzględnisz w wyszukiwaniu znaki specjalne wyrażenia regularne,sed będą do nich pasować. Dodaj -rflagę, jeśli zamiast tego chcesz użyć rozszerzonych elementów RE.
cscarney

32
@mcExchange Jeśli jest to konkretnie /znak, który musisz dopasować, możesz po prostu użyć innego znaku jako separatora (np 's_old/text_new/text_g'.). W przeciwnym razie możesz postawić \ przed dowolnym z nich, $ * . [ \ ^aby uzyskać dosłowny charakter.
cscarney,

3
@BrianZ Jeśli chodzi o system plików, wyjściem sed jest nowy plik o tej samej nazwie. Jest to jeden z najczęściej zgłaszanych błędów, które nie są błędami
cscarney

16
Polecenie OSX sed -i '.bak' 's/original/new/g' file.txtmożna również uruchomić z rozszerzeniem zerowej długości sed -i '' 's/original/new/g' file.txt, które nie wygeneruje kopii zapasowej.
Kirk,

19
Użytkownicy systemu MacOS będą musieli dodać „” po -i jako parametr dla -i ed.gs/2016/01/26/os-x-sed-invalid-command-code, aby plik został nadpisany.
geoyws

32

Można to zrobić na wiele różnych sposobów. Jeden używa sedi Regex. SED to Edytor strumienia do filtrowania i przekształcania tekstu. Jeden przykład jest następujący:

marco@imacs-suck: ~$ echo "The slow brown unicorn jumped over the hyper sleeping dog" > orly
marco@imacs-suck: ~$ sed s/slow/quick/ < orly > yarly
marco@imacs-suck: ~$ cat yarly
The quick brown unicorn jumped over the hyper sleeping dog

Innym sposobem, który może mieć większy sens niż < strini > stroutjest za pomocą rur!

marco@imacs-suck: ~$ cat yarly | sed s/unicorn/fox/ | sed s/hyper/lazy/ > nowai
marco@imacs-suck: ~$ cat nowai 
The quick brown fox jumped over the lazy sleeping dog

6
pamiętać, że catw cat file | sed '...'to niepotrzebne. Możesz bezpośrednio powiedzieć sed '...' file.
fedorqui

1
Rzeczywiście można to jeszcze bardziej zmniejszyć: sed -i'.bak' -e 's/unicorn/fox/g;s/hyper/brown/g' yarlyweźmie plik i wykona 2 zmiany w miejscu podczas tworzenia kopii zapasowej. Używając time bash -c "$COMMAND"czasu sugeruje, że ta wersja jest ~ 5 razy szybsza.
pbhj

23

Istnieje wiele sposobów na osiągnięcie tego. W zależności od złożoności tego, co próbuje się osiągnąć za pomocą zamiany łańcucha, oraz w zależności od narzędzi, z którymi użytkownik jest zaznajomiony, niektóre metody mogą być preferowane bardziej niż inne.

W tej odpowiedzi używam prostego input.txtpliku, którego można użyć do przetestowania wszystkich podanych tutaj przykładów. Zawartość pliku:

roses are red , violets are blue
This is an input.txt and this doesn't rhyme

GRZMOTNĄĆ

Bash nie jest tak naprawdę przeznaczony do przetwarzania tekstu, ale proste podstawienia można wykonać poprzez rozszerzenie parametrów , w szczególności tutaj możemy użyć prostej struktury ${parameter/old_string/new_string}.

#!/bin/bash
while IFS= read -r line
do
    case "$line" in
       *blue*) printf "%s\n" "${line/blue/azure}" ;;
       *) printf "%s\n" "$line" ;;
    esac
done < input.txt

Ten mały skrypt nie zastępuje w miejscu, co oznacza, że ​​musisz zapisać nowy tekst w nowym pliku i pozbyć się starego pliku lub mv new.txt old.txt

Uwaga dodatkowa: jeśli jesteś ciekawy, dlaczego while IFS= read -r ; do ... done < input.txtjest używany, jest to po prostu sposób czytania pliku wiersz po wierszu. Zobacz to w celach informacyjnych.

AWK

AWK, jako narzędzie do przetwarzania tekstu, jest całkiem odpowiednie do takiego zadania. Może dokonywać prostych zamian i znacznie bardziej zaawansowanych na podstawie wyrażeń regularnych . Zapewnia dwie funkcje: sub()i gsub(). Pierwszy zastępuje tylko pierwsze wystąpienie, a drugi - zastępuje wystąpienia całym ciągiem. Na przykład, jeśli mamy ciąg znaków one potato two potato, byłby to wynik:

$ echo "one potato two potato" | awk '{gsub(/potato/,"banana")}1'
one banana two banana

$ echo "one potato two potato" | awk '{sub(/potato/,"banana")}1'                                      
one banana two potato 

AWK może przyjmować plik wejściowy jako argument, więc robienie tych samych rzeczy input.txtbyłoby łatwe:

awk '{sub(/blue/,"azure")}1' input.txt

W zależności od wersji AWK, którą posiadasz, może ona mieć lub nie mieć edycji na miejscu, dlatego zwykłą praktyką jest zapisywanie i zastępowanie nowego tekstu. Na przykład coś takiego:

awk '{sub(/blue/,"azure")}1' input.txt > temp.txt && mv temp.txt input.txt

SED

Sed jest edytorem linii. Używa również wyrażeń regularnych, ale w przypadku prostych podstawień wystarczy wykonać:

sed 's/blue/azure/' input.txt

Zaletą tego narzędzia jest możliwość edycji w miejscu, którą można włączyć za pomocą -iflagi.

Perl

Perl to kolejne narzędzie, które jest często używane do przetwarzania tekstu, ale jest językiem ogólnego przeznaczenia i jest używane w sieci, administracji systemem, aplikacjach komputerowych i wielu innych miejscach. Pożyczył wiele pojęć / funkcji z innych języków, takich jak C, sed, awk i innych. Prostą zamianę można wykonać w następujący sposób:

perl -pe 's/blue/azure/' input.txt

Podobnie jak sed, perl ma również flagę -i.

Pyton

Ten język jest bardzo wszechstronny i jest również używany w wielu różnych aplikacjach. Ma wiele funkcji do pracy z łańcuchami, wśród których jest replace(), więc jeśli masz zmienną podobną var="Hello World", możesz to zrobićvar.replace("Hello","Good Morning")

Prostym sposobem na odczytanie pliku i zastąpienie w nim ciągu byłoby tak:

python -c "import sys;lines=sys.stdin.read();print lines.replace('blue','azure')" < input.txt

Jednak w Pythonie musisz także wyprowadzać dane do nowego pliku, co możesz również zrobić w samym skrypcie. Na przykład oto prosty:

#!/usr/bin/env python
import sys
import os
import tempfile

tmp=tempfile.mkstemp()

with open(sys.argv[1]) as fd1, open(tmp[1],'w') as fd2:
    for line in fd1:
        line = line.replace('blue','azure')
        fd2.write(line)

os.rename(tmp[1],sys.argv[1])

Ten skrypt należy wywoływać input.txtjako argument wiersza polecenia. Dokładna komenda do uruchomienia skryptu Pythona z argumentem wiersza poleceń to

 $ ./myscript.py input.txt

lub

$ python ./myscript.py input.txt

Oczywiście upewnij się, że ./myscript.pyznajduje się on w bieżącym katalogu roboczym i po pierwsze upewnij się, że jest ustawiony na plik wykonywalnychmod +x ./myscript.py

Python może również mieć wyrażenia regularne, w szczególności jest remoduł, który ma re.sub()funkcję, której można użyć do bardziej zaawansowanych zamian.


1
Niezła kompilacja! Innym możliwym sposobem niewymienionym tutaj jest użycie trpolecenia w
unixie

1
@TapajitDey Tak, tr jest kolejnym doskonałym narzędziem, ale należy pamiętać, że służy on do zastępowania zestawów znaków (na przykład tr abc cdetłumaczyłby ana c, bto d. Różni się nieco od zastępowania całych słów, jak za pomocą sedlubpython
Sergiy Kolodyazhnyy

22

Możesz używać Vima w trybie Ex:

ex -s -c '%s/OLD/NEW/g|x' file
  1. % wybierz wszystkie linie

  2. s zastąpić

  3. g zamień wszystkie wystąpienia w każdej linii

  4. x napisz, jeśli dokonano zmian (mają) i wyjdź


21

Poprzez polecenie gsub awk,

awk '{gsub(/pattern/,"replacement")}' file

Przykład:

awk '{gsub(/1/,"0");}' file

W powyższym przykładzie wszystkie 1 są zastępowane przez 0 bez względu na kolumnę, w której się znajdują.


Jeśli chcesz zrobić zamianę w określonej kolumnie, zrób tak,

awk '{gsub(/pattern/,"replacement",column_number)}' file

Przykład:

awk '{gsub(/1/,"0",$1);}' file

Zastępuje 1 z 0 tylko w pierwszej kolumnie.

Poprzez Perla,

$ echo 'foo' | perl -pe 's/foo/bar/g'
bar

Użyłem tego na terminalu MacOS i nic nie zrobiło ...
Jim

Testowany na Alpine Linux (w kontenerze Docker) i nie otrzymał danych wyjściowych
Salathiel Genèse

@ SalathielGenèse, co próbujesz osiągnąć?
Avinash Raj

Patrzę plik z inotifywaitpod shenv, a dane w formacie CSV raportowanie (bo Format niestandardowy jest wadliwy). Uznałem wtedy, że nie ma prostego sposobu obsługi dokumentu CSV w skryptach powłoki ... I chcę, żeby był bardzo lekki. Więc zacząłem dość prosty skrypt do analizowania i raportowania CSV. Przeczytałem specyfikację CSV i zauważyłem, że jest bardziej rozbudowana niż się spodziewałem i obsługuje wartość wielowierszową opakowaną w podwójne cudzysłowy. Byłem powołując się sedna tokeny, ale szybko zorientował się, że nawet co sedmultilinie zadzwonić wynosi do dwóch linii. Co wtedy, gdy jedna z moich wartości CSV obejmuje więcej niż dwie linie?
Salathiel Genèse

lepiej zadaj swój problem jako pytanie.
Avinash Raj

8

sedjest s TREAM ed itor , w których można użyć |(rury) do wysyłania standardowych strumieni (stdin i stdout konkretnie) przez sedi zmieniać je programowo w locie, co czyni go przydatnym narzędziem w tradycji filozofii Unix; ale może również edytować pliki bezpośrednio, używając -iparametru wymienionego poniżej.
Rozważ następujące kwestie :

sed -i -e 's/few/asd/g' hello.txt

s/stosuje się S ubstitute znaleziony ekspresji fewz asd:

Nieliczni, odważni.


Asd, odważny.

/goznacza „globalny”, co oznacza, że ​​należy to zrobić dla całej linii. Jeśli odrzucisz /g(z s/few/asd/, zawsze muszą być trzy ukośniki bez względu na wszystko) i fewpojawi się dwa razy w tej samej linii, tylko pierwsza fewzostanie zmieniona na asd:

Tych niewielu mężczyzn, kilka kobiet, odważnych.


Asd mężczyźni, kilka kobiet, odważny.

Jest to przydatne w niektórych okolicznościach, na przykład zmieniając znaki specjalne na początku wiersza (na przykład zastępując symbole większe niż niektóre osoby używają do cytowania poprzedniego materiału w wątkach wiadomości e-mail za pomocą poziomej tabulacji, pozostawiając cytowaną nierówność algebraiczną później w wierszu nietknięte), ale w twoim przykładzie, w którym określasz, że gdziekolwiek few występuje, należy go wymienić, upewnij się, że go masz /g.

Następujące dwie opcje (flagi) są połączone w jedną -ie:

-iOpcja ta służy do edycji i n umieścić w pliku hello.txt.

-eOpcja wskazuje e Xpression / polecenie do uruchomienia, w tym przypadku s/.

Uwaga: Ważne jest, aby używać -i -edo wyszukiwania / zastępowania. Jeśli to zrobisz -ie, utworzysz kopię zapasową każdego pliku z dołączoną literą „e”.


2

Możesz to zrobić w następujący sposób:

locate <part of filaname to locate> | xargs sed -i -e "s/<Old text>/<new text>/g" 

Przykłady: aby zamienić wszystkie wystąpienia [logdir ',' '] (bez []) na [logdir', os.getcwd ()] we wszystkich plikach będących wynikiem polecenia locate, wykonaj:

ex1:

locate tensorboard/program.py | xargs sed -i -e "s/old_text/NewText/g"

ex2:

locate tensorboard/program.py | xargs sed -i -e "s/logdir', ''/logdir', os.getcwd()/g"

gdzie [tensorboard / program.py] to plik do przeszukania


Cześć. Twój wybór ciągów ( logdir', ''-> /logdir', os.getcwd()) sprawia, że ​​odpowiedź jest trudna do przeanalizowania. Warto również określić, że twoja odpowiedź najpierw lokalizuje pliki, na których ma być używany sed, ponieważ nie jest to częścią pytania.
mwfearnley

Cześć, ta odpowiedź dotyczy zarówno wyszukiwania, jak i zamiany wszystkich, jeśli znalazła <stary tekst> w pliku.
Nguyễn Tuấn Anh

Wybieram tę odpowiedź dla wszystkich, którzy używają tensorboardu w keras, którzy chcą zmienić polecenie z: tensorboard --logdir = '/ path / to / log / folder /', aby używać: tylko tensorboard, pozostając w folderze logów. jest to bardzo wygodne
Nguyễn Tuấn Anh
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.