Zapisz modyfikacje w miejscu za pomocą awk

140

Uczę się awki chciałbym wiedzieć, czy jest możliwość zapisania zmian do pliku, podobnie jak w sedprzypadku, gdybym skorzystał z -iopcji zapisywania zmian w pliku.

Rozumiem, że mógłbym użyć przekierowania do zapisania zmian. Czy jest jednak opcja, awkaby to zrobić?

Deano
źródło
W przypadku, gdyby ktoś chciał mieć zapis w miejscu z NON GNU, awkmoże użyć poniższego linku również stackoverflow.com/questions/59243104/ ... fyi, proszę.
RavinderSingh

Odpowiedzi:

150

W GNU Awk 4.1.0 (wydanym 2013) i nowszych ma opcję edycji plików „inplace” :

[...] Rozszerzenie "inplace", zbudowane przy użyciu nowego narzędzia, może być użyte do symulacji funkcji GNU " sed -i". […]

Przykładowe użycie:

$ gawk -i inplace '{ gsub(/foo/, "bar") }; { print }' file1 file2 file3

Aby zachować kopię zapasową:

$ gawk -i inplace -v INPLACE_SUFFIX=.bak '{ gsub(/foo/, "bar") }
> { print }' file1 file2 file3
Lind
źródło
Wygląda na to, że opcja została usunięta? W wersji 4.1.3 mam "-i includeefile --include = includeefile"
Keith Hughitt
1
@Keith Miałem to samo pytanie. Właśnie go wypróbowałem i działa na moim 4.1.3. inplacejest właściwie biblioteką dołączoną gawkzgodnie z odpowiedzią iiSeymour , więc inplacejest to coś, co można dołączyć jako plik includefile.
cxw
Ważne ostrzeżenie: tablica „seen” zapełni się zduplikowanymi wierszami ze WSZYSTKICH plików zawartych w poleceniu. Więc jeśli każdy plik ma np. Wspólny nagłówek, zostanie on usunięty w każdym pliku po pierwszym. Jeśli zamiast tego chcesz traktować każdy plik niezależnie, musisz zrobić coś takiego jak dla f w * .txt; do gawk -i inplace '! seen [$ 0] ++' "$ f"; gotowe
Nick K9
140

Chyba że masz GNU awk 4.1.0 lub nowszy ...

Nie będziesz mieć takiej opcji jak opcja seda, -iwięc zamiast tego zrób:

$ awk '{print $0}' file > tmp && mv tmp file

Uwaga: -ito nie jest magia, to również tworzenie pliku tymczasowego, który sedobsługuje go za Ciebie.


Od GNU awk 4.1.0 ...

GNU awkdodano tę funkcjonalność w wersji 4.1.0 (wydana 05.10.2013) . Nie jest to tak proste, jak po prostu podanie -iopcji, jak opisano w opublikowanych uwagach:

Nowa opcja -i (z xgawk) służy do ładowania plików bibliotek awk. Różni się to od -f tym, że pierwszy argument niebędący opcją jest traktowany jako skrypt.

Aby inplace.awkpoprawnie wywołać rozszerzenie, musisz użyć dołączonego pliku dołączanego :

$ cat file
123 abc
456 def
789 hij

$ gawk -i inplace '{print $1}' file

$ cat file
123
456
789

Zmiennej INPLACE_SUFFIXmożna użyć do określenia rozszerzenia pliku kopii zapasowej:

$ gawk -i inplace -v INPLACE_SUFFIX=.bak '{print $1}' file

$ cat file
123
456
789

$ cat file.bak
123 abc
456 def
789 hij

Cieszę się, że ta funkcja została dodana, ale dla mnie implementacja nie jest zbyt dziwna, ponieważ moc pochodzi ze zwięzłości języka i -i inplacejest o 8 znaków za długa imo .

Oto link do podręcznika z oficjalnym słowem.

Chris Seymour
źródło
Czy twój „pierwszy” przykład nie powinien bardziej przypominać awk '{ gsub(/foo/, "bar" ) } ; { print $0 }' file > tmp.txt && mv -v tmp.txt file:?
Tony Barganski
Ku mojemu zdziwieniu od kwietnia 2019 r. Nadal na gawk 4.0.2. Nie pozwól nikomu powiedzieć Ci takiej, a taka wersja będzie dostępna.
John Lunzer
Trochę krócej awk '{print $0}' file | sponge fileprzy użyciu spongeod moreutils.
brablc
19

tylko mały hack, który działa

echo "$(awk '{awk code}' file)" > file
Jurij G.
źródło
Działa jak marzenie! Ale czy można zapisać polecenie awk do zmiennej i po prostu użyć go w swojej sprytnej sztuczce?
ashrasmun
Do -i inplaceprzerwy metoda hardlinki ten siekać następująco hardlinki ♥♥
Sandra
16

@sudo_O ma właściwą odpowiedź .

To nie może działać:

someprocess < file > file

Powłoka wykonuje przekierowania przed przekazaniem kontroli do jakiegoś procesu ( przekierowania ). >Przekierowania będzie obcina pliku zerowej wielkości ( wyjściowego przekierowanie ). Dlatego zanim jakiś proces zostanie uruchomiony i chce odczytać z pliku, nie ma danych do odczytania.

glenn jackman
źródło
13

Alternatywą jest użycie sponge:

awk '{print $0}' your_file | sponge your_file

Gdzie zastępujesz '{print $0}'skryptem awk i your_filenazwą pliku, który chcesz edytować w miejscu.

sponge całkowicie pochłania dane wejściowe przed zapisaniem ich do pliku.

Codoscope
źródło
Jak standardowa / przenośna jest gąbka?
Thomas
2
spongejest częścią moreutils. Więc nie będzie domyślnie obecny w większości systemów. Ale wygląda na to, że przynajmniej spongesam jest wystarczająco przenośny i można go uruchomić prawie wszędzie.
MarSoft,
2
Wadą tego rozwiązania w porównaniu do tee-based jest to, że spongeprzed zapisaniem odczyta wszystko do pamięci RAM, dlatego będzie się zawieszać na dużych plikach.
MarSoft,
6

śledzenie nie będzie działać

echo $(awk '{awk code}' file) > file

to powinno działać

echo "$(awk '{awk code}' file)" > file
Flowmix Leonsio
źródło
3

W przypadku, gdy potrzebujesz rozwiązania tylko awk bez tworzenia pliku tymczasowego i nadającego się do użytku z wersją! = (Gawk 4.1.0):

awk '{a[b++]=$0} END {for(c=0;c<=b;c++)print a[c]>ARGV[1]}' file
Jastrząb
źródło
4
Ale czy to buforuje cały plik w pamięci? Rozważ plik o rozmiarze 20 GB.
Amit Naidu
-3

Korzystanie z koszulki

 awk '{awk code}' file | tee file

teemiejsce odbioru i polecenia wykonywane po awkkomenda jest zakończona ze względu na |.

shaiki siegal
źródło
8
To jest niepoprawne. Te dwa polecenia są wykonywane równolegle, a dane są natychmiast przesyłane strumieniowo przez potok. Każdy plik większy niż bufor (8192 bajty na moim komputerze) zostanie obcięty, a dane zostaną utracone.
tripflag