Znajdź i zamień w pliku, a plik zastępowania nie działa, opróżnia plik


604

Chciałbym uruchomić wyszukiwanie i zastąpić w pliku HTML za pomocą wiersza polecenia.

Moje polecenie wygląda mniej więcej tak:

sed -e s/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g index.html > index.html

Kiedy uruchamiam to i potem patrzę na plik, jest on pusty. Usunął zawartość mojego pliku.

Kiedy uruchomię to po przywróceniu pliku:

sed -e s/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g index.html

Jest stdoutto zawartość pliku, a wyszukiwanie i zamiana zostały wykonane.

Dlaczego to się dzieje?


13
Alternatywa dla Perla:perl -pi -w -e 's/STRING_TO_REPLACE/REPLACE_WITH/g;' index.html
Gjorgji Tashkovski

bardzo podobne sedpolecenie, aby znaleźć ciąg i zastąpić całą linię: stackoverflow.com/questions/11245144/…
cregox

Odpowiedzi:


917

Gdy powłoka widzi > index.htmlw wierszu poleceń, otwiera plik index.htmldo zapisu , usuwając całą swoją poprzednią zawartość.

Aby to naprawić, musisz przekazać -iopcję, aby sedwprowadzić zmiany bezpośrednio i utworzyć kopię zapasową oryginalnego pliku, zanim dokona on zmian w miejscu:

sed -i.bak s/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g index.html

Bez .bak polecenie nie powiedzie się na niektórych platformach, takich jak Mac OSX.


20
Mówienie truncates the filezamiast opens the fileprawdopodobnie czyni to jaśniejszym.
Mikel

12
Przynajmniej na moim komputerze Mac pierwsza sugestia nie działa ... jeśli zastępujesz plik w miejscu, musisz określić rozszerzenie. Możesz przynajmniej przekazać rozszerzenie zerowej długości: sed -i '' / STRING_TO_REPLACE / STRING_TO_REPLACE_IT / g index.html
Tom Lianza

5
dla zmiennych sed -i.bak 's /' $ search '/' $ replace '/ g' index.html
Fatima Zohra

33
na osx, użyj pustego łańcucha '' jako parametru -i, na przykład:sed -i '' 's/blah/xx/g'
Pierre Houston

4
ale co do ciebie .bakpo sed -i?
Patrizio Bertoni,

210

Alternatywnym, użytecznym wzorem jest:

sed -e 'script script' index.html > index.html.tmp && mv index.html.tmp index.html

Ma to ten sam efekt, bez użycia -iopcji, a dodatkowo oznacza, że ​​jeśli skrypt sed z jakiegoś powodu zawiedzie, plik wejściowy nie zostanie zablokowany. Ponadto, jeśli edycja się powiedzie, nie będzie leżącego pliku kopii zapasowej. Ten rodzaj idiomu może być przydatny w Makefiles.

Wiele seds ma taką -iopcję, ale nie wszystkie; posix sed to taki, który tego nie robi. Jeśli więc zależy Ci na przenośności, najlepiej tego unikać.


9
+1 za brak pliku kopii zapasowej i nie blokowanie pliku wejściowego, jeśli edycja się nie powiedzie. Działa bezbłędnie na Macu.
Mike Grace

Pracował dla mnie idealnie. Dziękuję Ci! (na komputerze Mac)
zainteresowany

1
Działa to dla mnie idealnie, gdy na Ubuntu Server 14.04 sed -i ciągle zerował plik.
Chris Giddings,

2
Niezwykle niewielkie ulepszenie:... && mv index.html{.tmp,}
EdwardGarson

5
@EdwardGarson Rzeczywiście, prawdopodobnie tego bym użył, gdybym to pisał - zgadzam się, że jest fajniejszy - ale sh(jeśli dobrze pamiętam) nie ma tego {...}rozszerzenia. W Makefile możesz shraczej używać niż bash, więc jeśli dążysz do przenośności (lub posixness), musisz unikać takiej konstrukcji.
Norman Gray,

95
sed -i 's/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g' index.html

Dokonuje to globalnego podstawienia lokalnego w pliku index.html. Cytując ciąg zapobiega problemom z białymi znakami w zapytaniu i zamianie.


57

użyj opcji -i, np

sed -i bak -e s/STRING_TO_REPLACE/REPLACE_WITH/g index.html

Co to znaczy? sed: -i nie może być używany ze standardowym
arkuszowym

2
Pamiętaj, aby otaczać wzór cytatem, jeśli zawiera spacje -'s/STRING_TO_REPLACE/REPLACE_WITH/g'
Doug Thompson

@ sheheal: -iwykonuje edycję plików na miejscu , więc nie ma sensu łączyć ich z wejściem standardowym .
mklement0

To może działać na macOS, ale nie działa na Arch Linux.
xdevs23,

Bez -e zaakceptowana odpowiedź nie działa na MacOS, Catalina. Z -e działa.
cwhiii

18

Aby zmienić wiele plików (i zapisać kopię zapasową każdego pliku jako * .bak):

perl -p -i -e "s/\|/x/g" *  

weźmie wszystkie pliki w katalogu i wymienić |z x tego nazywany jest „Perl pie” (łatwe, jak ciasto)


1
Dobrze widzieć kogoś, kto chce przejrzeć opis problemu, a nie tylko tagi. OP nie został określony sedjako wymaganie, wykorzystał go tylko jako narzędzie, które już wypróbowano.
user7412956,


6
sed -i.bak "s#https.*\.com#$pub_url#g" MyHTMLFile.html

Jeśli masz link do dodania, spróbuj tego. Wyszukaj adres URL jak powyżej (zaczynając od https i kończąc na.com tutaj) i zastąp go ciągiem URL. Użyłem $pub_urltutaj zmiennej . stutaj oznacza wyszukiwanie i goznacza globalną wymianę.

To działa !


6

Ostrzeżenie: to niebezpieczna metoda! Nadużywa buforów we / wy w systemie Linux i dzięki konkretnym opcjom buforowania zarządza pracą na małych plikach. To ciekawa ciekawość. Ale nie używaj go do prawdziwej sytuacji!

Poza -iopcją sed można użyć teenarzędzia .

Od man:

tee - odczyt ze standardowego wejścia i zapis na standardowe wyjście i pliki

Tak więc rozwiązaniem byłoby:

sed s/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g index.html | tee | tee index.html

- tutaj teepowtarza się, aby upewnić się, że rurociąg jest buforowany. Następnie wszystkie polecenia w potoku są blokowane, dopóki nie uzyskają danych wejściowych do pracy. Każde polecenie w potoku rozpoczyna się, gdy poprzedzające polecenia zapisują 1 bufor bajtów ( gdzieś rozmiar jest zdefiniowany ) na wejściu polecenia. Tak więc ostatnie polecenie tee index.html, które otwiera plik do zapisu i dlatego go opróżnia, jest uruchamiane po zakończeniu potoku wyjściowego i wyjściu znajduje się w buforze w potoku.

Najprawdopodobniej następujące elementy nie będą działać:

sed s/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g index.html | tee index.html

- uruchomi oba polecenia potoku w tym samym czasie, bez blokowania. (Bez blokowania gazociąg powinien przechodzić linię bajty po linii zamiast buforu przez bufor. Tak samo jak podczas uruchamiania cat | sed s/bar/GGG/. Bez blokowania jest bardziej interaktywny i zazwyczaj rurociągi zaledwie 2 poleceń uruchomić bez buforowania i blokowania. Dłuższe rurociągi są buforowane.) The tee index.htmlwoli otwórz plik do zapisu i zostanie on opróżniony. Jeśli jednak zawsze włączasz buforowanie, druga wersja również będzie działać.


3
Plik wyjściowy tee jest również natychmiast otwierany, co skutkuje pustym plikiem index.html dla całego polecenia.
sjngm

3
Spowoduje to uszkodzenie dowolnego pliku wejściowego, który jest większy niż bufor potoku (zwykle jest to 64 KB) . (@sjngm: plik nie jest obcinany natychmiast jak w przypadku >, ale chodzi o to, że jest to zepsute rozwiązanie, które może spowodować utratę danych).
mklement0

4

Problem z poleceniem

sed 'code' file > file

jest to, że filejest obcinane przez powłokę, zanim sed faktycznie ją przetworzy. W rezultacie otrzymujesz pusty plik.

Sed to sposób na -iedycję w miejscu, jak sugerowały inne odpowiedzi. Nie zawsze jest to jednak to, czego chcesz. -iutworzy plik tymczasowy, który zostanie następnie użyty do zastąpienia oryginalnego pliku. Jest to problematyczne, jeśli oryginalny plik był linkiem (link zostanie zastąpiony zwykłym plikiem). Jeśli chcesz zachować łącza, możesz użyć zmiennej tymczasowej do przechowywania danych wyjściowych sed przed zapisaniem ich z powrotem do pliku, w następujący sposób:

tmp=$(sed 'code' file); echo -n "$tmp" > file

Jeszcze lepiej, użycie printfzamiast echoponieważ echojest prawdopodobne, aby proces \\jak \w niektórych muszli (np kreska):

tmp=$(sed 'code' file); printf "%s" "$tmp" > file

1
+1 za zachowanie linków. Działa również z plikiem tymczasowym:sed 'code' file > file.tmp; cat file.tmp > file; rm file.tmp
dashohoxha

3

I edodpowiedź:

printf "%s\n" '1,$s/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g' w q | ed index.html

Aby powtórzyć odpowiedź na kodaddict , powłoka najpierw obsługuje przekierowanie , usuwając plik „input.html”, a następnie powłoka wywołuje polecenie „sed”, przekazując mu teraz pusty plik.


2
szybkie pytanie, dlaczego ludzie wciąż udzielają „ edwersji” sedodpowiedzi? czy działa szybciej?
cregox

6
Niektóre seds nie implementują -ido edycji w miejscu. edjest wszechobecny i pozwala zapisywać zmiany w oryginalnym pliku. Ponadto zawsze dobrze jest mieć wiele narzędzi w zestawie.
glenn jackman

ok fajnie. więc pod względem wydajności przypuszczam, że są takie same. dzięki!
cregox

2

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

ex -sc '%s/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g|x' index.html
  1. % wybierz wszystkie linie

  2. x Zapisz i zamknij


0

Szukałem opcji, w której mogę zdefiniować zakres linii i znalazłem odpowiedź. Na przykład chcę zmienić host1 na host2 z linii 36-57.

sed '36,57 s/host1/host2/g' myfile.txt > myfile1.txt

Możesz również użyć opcji gi, aby zignorować wielkość liter.

sed '30,40 s/version/story/gi' myfile.txt > myfile1.txt

0

Z całym szacunkiem dla powyższych poprawnych odpowiedzi, zawsze dobrym pomysłem jest uruchamianie takich skryptów „na sucho”, aby nie uszkodzić pliku i zacząć od nowa.

Wystarczy, że skrypt rozleje dane wyjściowe do wiersza poleceń zamiast zapisywać je w pliku, na przykład w ten sposób:

sed -e s/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g index.html

LUB

less index.html | sed -e s/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g 

W ten sposób możesz zobaczyć i sprawdzić dane wyjściowe polecenia bez obcinania pliku.

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.