2012-05-31 9 views
40

Próbuję użyć polecenia sed w skrypcie powłoki, w którym chcę usunąć linie, które czytają STARTremoveThisComment i linie, które czytają removeThisCommentEND.Jak uruchomić polecenie sed z wejściem i wyjściem jako tym samym plikiem?

jestem w stanie to zrobić, kiedy skopiować go do nowego pliku przy użyciu

sed 's/STARTremoveThisComment//' > test 

Ale jak mam to zrobić przy użyciu tego samego pliku jako wejścia i wyjścia?

+1

sed -es/Some1/some2/g input.file> output.file mv output.file input.file – 0xAX

Odpowiedz

72

sed -i (lub wersja rozszerzona, --in-place) będzie zautomatyzować proces zazwyczaj wykonane z mniej zaawansowanych wdrożeń, że wysyłanie wyjście do pliku tymczasowego, a następnie zmiana nazwy, że z powrotem do oryginału.

-i jest do edycji w miejscu, a można również dostarczyć do przechowywania kopii zapasowych przyrostek kopię oryginału:

sed -i.bak fileToChange 
sed --in-place=.bak fileToChange 

Oba te zachowa oryginalny plik w fileToChange.bak.

Należy pamiętać, że w miejscu edycji może nie być dostępna we wszystkich sed wdrożeń ale jest w GNU sed, które powinny być dostępne we wszystkich odmianach Linuksa, jak na swoje znaczniki.

Jeśli używasz bardziej prymitywne wykonanie, można użyć coś takiego:

sed 'whatever' oldfile >newfile ; mv newfile oldfile 

choć niektóre bardziej sprawdzanie błędów byłoby miło.

+1

pracował jak urok! :) to jest to, czego użyłem: 'sed -i 's/STARTremoveThisComment //' test' –

+1

Zauważ, że' --in-place' jest gnuizmem i nie będzie działać we wszystkich wersjach sed. Jeśli chcesz używać skryptu sed na maszynach innych niż Linux, nie możesz z niego korzystać. –

+0

@william, pomyślałem o tym, ale nie był zbyt poruszony, ponieważ pytanie miało tag Linuksa. Wyjaśnię. – paxdiablo

0

O ile mi wiadomo, nie jest możliwe użycie tego samego pliku dla wejścia i wyjścia. Chociaż jednym z rozwiązań jest utworzenie skryptu powłoki, który zapisze go w innym pliku, usunie stare dane wejściowe i zmieni nazwę pliku wyjściowego na nazwę pliku wejściowego.

sed -e s/try/this/g input.file > output.file;mv output.file input.file 
+2

Przynajmniej jeżeli nie jest to „SED. .. & mv ... "więc błąd sed nie zastąpi danych wejściowych pustym plikiem? –

5

Naprawdę nie powinieneś używać sed do tego. Wydaje się, że to pytanie wydaje się często absurdalnie często i wydaje się bardzo dziwne, że tak, ponieważ ogólne rozwiązanie jest tak banalne, wydaje się dziwne, że ludzie chcą wiedzieć, jak to zrobić w sed, w python, w rubinach itd. . Jeśli chcesz mieć filtr działać na wejściu i zastąpić go, kliknąć na poniższy prosty skrypt:

#!/bin/sh -e 
in=${1?No input file specified} 
mv $in ${bak=.$in.bak} 
shift 
"[email protected]" < $bak > $in 

umieścić, że na swojej drodze w nazwa pliku wykonywalnego inline, a następnie problem jest rozwiązany w ogóle. Na przykład:

inline input-file sed -e s/foo/bar/g 

Teraz, jeśli chcesz dodać logikę do przechowywania wielu kopii zapasowych, lub jeśli masz kilka opcji, aby zmienić schemat nazewnictwa kopii zapasowej, czy cokolwiek, to naprawić w jednym miejscu. Jaka jest opcja wiersza poleceń, aby uzyskać liczniki jednopozycyjne w pliku kopii zapasowej podczas przetwarzania pliku na miejscu przy użyciu perl? A co z numerem ruby? Czy ta opcja jest inna w przypadku gnu-sed? Jak radzi sobie z tym awk? Cały friggin 'point of unix jest taki, że narzędzia robią tylko jedno. Obsługa logiki dla plików kopii zapasowych jest drugą kwestią i należy ją rozważyć. Jeśli wdrażasz narzędzie, nie dodawaj logiki do tworzenia plików kopii zapasowych. Poinformuj użytkowników o użyciu drugiego narzędzia. Integracja jest zła. Modułowość jest dobra. To jest sposób uniksowy.

Należy zauważyć, że ten skrypt ma kilka problemów.Uprawnienia/tryb pliku wejściowego mogą na przykład zostać zmienione. Jestem pewien, że są niezliczone inne problemy. Jednak umieszczając logikę kopii zapasowej w skrypcie otoki, lokalizujesz wszystkie te problemy i nie musisz się martwić, że sed nadpisuje tryb plików i zmian, podczas gdy python utrzymuje plik na miejscu i nie zmienia i-węzła (zrobiłem się tych dwóch przypadkach, punkt jest, że nie wszystkie narzędzia będą używać tej samej logiki, natomiast skrypt wrapper będzie.)

+0

Dzięki, podoba mi się scenariusz i dostosowałem go do mojego gustu #!/Bin/sh -e in = $ { 1? Nie podano pliku wejściowego} mv "$ in" $ {bak = in.bak} przesunięcie "$ @" < "$bak" > $ w && rm "$ bak" || mv "$ bak" "$ in" –

+2

Nie zgadzam się, jeśli 'sed' ma jakąś funkcję, to nie widzę powodu, aby tego nie robić. Wydaje się również pasować do tego, czego chce. – markzz

+0

@MarkWeiman Problem polega na tym, że "sed" nie ma tej funkcji. Jedna konkretna implementacja sed obsługuje tę funkcję, a gdy tylko spróbujesz przenieść skrypt na maszynę, która używa innej implementacji, skrypt się zepsuje. –

5

Możesz użyć flagi -i do edycji w miejscu i -e dla określenie normalnego wyrażenia skryptu:

sed -i -e 's/pattern_to_search/text_to_replace/' file.txt 

Aby usunąć linie pasujące do określonego wzoru, może użyć prostszej składni. Zauważyć d flag

sed -i '/pattern_to_search/d' file.txt 
+0

na moim Macu to również tworzy kopię oryginalnego pliku, jak np. File.txt-e, dlaczego? – SuperUberDuper

+0

czy pozostawiasz spację pomiędzy -i i -e? ponieważ w przeciwnym razie traktuje jako -e SUFFIX jako kopię zapasową. Pomoc Sed'a pokazuje opis plików--i [SUFFIX], - in-place [= SUFFIX] -i -i (SUFFIX) w miejscu (tworzy kopię zapasową, jeśli dostarczono SUFFIX) ' Właśnie przetestowałem to ponownie na moim komputerze z Linuksem i działa dobrze. – Tiago

Powiązane problemy