Awk ile değişiklikleri yerinde kaydedin


135

Öğreniyorum awkve değişiklikleri bir dosyaya kaydetme seçeneğini sedkullanacağım yere benzer şekilde, dosyaya değişiklik yazma seçeneği olup olmadığını öğrenmek istiyorum -i.

Değişiklikleri yazmak için yeniden yönlendirmeyi kullanabileceğimi anlıyorum. Ancak awkbunu yapmak için bir seçenek var mı?


"Yeniden yönlendirme ile bir dosyayı yerinde düzenleme" nin daha genel yanıtı için serverfault.com/a/547331/313521 adresine de bakın .
Wildcard

@Wildcard. Buradaki çözüm korkunç derecede kırılgan. Olayların sıralanması konusunda kesinlikle hiçbir garanti yoktur ve bu çözümü kullanmak verilerinizi kesebilir. Bir kenara, o sitede doğrudan yorum yapamam çünkü bunu yapmak için o sitede 50 temsilciye ihtiyacım var. SO'nun neden Unix / Linux ve sunucu yöneticisi ve diğerlerine bölündüğünü asla anlayamayacağım. IMO, bu bir hataydı.
William Pursell

@WilliamPursell, "olayların sıralanması konusunda garanti yoktur" - bu aslında yanlıştır. Çözümün sahip olduğu tek kırılganlık, içeriklerin uzunluğunun bir komut için maksimum uzunluktan daha büyük olmasıdır. Bununla birlikte, olayların sıralaması garantilidir.
Wildcard

@Wildcard Hangi standart bu siparişi garanti ediyor?
William Pursell

@WilliamPursell, bash dokümantasyonu ile garantilidir. Diğer mermiler için bilmiyorum. (Bu arada, hesabınızı bağlarsanız, 100 temsilci ilişkilendirme bonusunuz olacak ve yorum yapabileceksiniz.)
Wildcard

Yanıtlar:


142

En son GNU Awk'de ( 4.1.0 yayımlandığından beri ), "yerinde" dosya düzenleme seçeneğine sahiptir :

[...] Yeni tesis kullanılarak oluşturulan "yerinde" uzantı, GNU " sed -i" özelliğini simüle etmek için kullanılabilir . [...]

Örnek kullanım:

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

Yedeklemeyi saklamak için:

$ gawk -i inplace -v INPLACE_SUFFIX=.bak '{ gsub(/foo/, "bar") }
> { print }' file1 file2 file3

1
@sudo_O - "Yerinde" gösteri için teşekkürler. Cevabınızı olumlu oyladı!
lind

Seçenek kaldırılmış gibi görünüyor? 4.1.3 sürümüyle "-i includefile --include = includefile" var
Keith Hughitt

1
@Keith aynı soruyu sormuştum. Sadece denedim ve 4.1.3'ümde çalışıyor. inplaceAslında birlikte bir kütüphane gawkgöre iiSeymour cevabı , bu nedenle inplacebir şekilde dahil edilebilir bir şeydir includefile.
cxw

Burada önemli bir uyarı: 'görülen' dizisi, komutta bulunan TÜM dosyalardan gelen yinelenen satırlarla doldurulacaktır. Dolayısıyla, her dosyanın örneğin ortak bir başlığı varsa, bu ilk dosyadan sonra her dosyadan kaldırılacaktır. Bunun yerine her dosyayı bağımsız olarak ele almak istiyorsanız, f in * .txt gibi bir şey yapmanız gerekir; do gawk -i yerinde '! görüldü [$ 0] ++' "$ f"; bitti
Nick K9

136

GNU awk 4.1.0 veya sonrasına sahip değilseniz ...

Sed seçeneği gibi bir seçeneğiniz olmayacak, -ibunun yerine şunu yapın:

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

Not: -iSihir değil, aynı zamanda geçici bir dosya oluşturmak sedsadece sizin için ilgilenir.


GNU awk 4.1.0'dan itibaren ...

GNU awkbu işlevi 4.1.0 sürümünde ekledi (10/05/2013 tarihinde yayınlandı) . -iSerbest bırakılan notlarda açıklandığı gibi seçeneği vermek kadar düz bir ilerleme değildir :

Yeni -i seçeneği (xgawk'tan) awk kitaplık dosyalarını yüklemek için kullanılır. Bu, -f'den farklıdır, çünkü ilk seçenek olmayan bağımsız değişken bir komut dosyası olarak ele alınır.

inplace.awkUzantıyı aşağıdaki gibi düzgün bir şekilde çağırmak için birlikte verilen içerme dosyasını kullanmanız gerekir :

$ cat file
123 abc
456 def
789 hij

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

$ cat file
123
456
789

Değişken INPLACE_SUFFIX, bir yedekleme dosyasının uzantısını belirtmek için kullanılabilir:

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

$ cat file
123
456
789

$ cat file.bak
123 abc
456 def
789 hij

Bu özellik eklendi mutluyum ama güç dilinin özlü geliyor gibi bana, uygulaması çok awkish değil -i inplaceçok uzun 8 karakterdir imo .

Resmi kelime için kılavuza bir bağlantı .


'İlk' örneğiniz daha çok şuna benzemez awk '{ gsub(/foo/, "bar" ) } ; { print $0 }' file > tmp.txt && mv -v tmp.txt filemi?
Tony Barganski

Sürpriz bir şekilde, Nisan 2019 itibariyle, hala gawk 4.0.2'de. Kimsenin size böyle bir şey söylemesine izin vermeyin, böyle bir sürüm mevcut olacaktır.
John Lunzer

Litte kısa awk '{print $0}' file | sponge filekullanılarak spongeelde moreutils.
brablc


14

işe yarayan küçük bir hack

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

Tıkır tıkır çalışıyor! Ama awk komutunu değişkene kaydetmek ve sadece şık numaranızda kullanmak mümkün müdür?
ashrasmun

13

Bir alternatif kullanmaktır sponge:

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

'{print $0}'Awk betiğinizle değiştirdiğiniz yer veyour_file dosyanın adıyla yerinde düzenlemek istiyoruz.

sponge girdiyi dosyaya kaydetmeden önce tamamen emer.


Sünger ne kadar standart / taşınabilir?
Thomas

2
spongeparçasıdır moreutils. Bu yüzden çoğu sistemde varsayılan olarak mevcut olmayacaktır. Ama en azından spongekendisi yeterince taşınabilir gibi görünüyor ve neredeyse her yerde çalıştırılabilir.
MarSoft

1
Bu çözümün tee-based ile karşılaştırıldığında dezavantajı, spongeyazmadan önce her şeyi RAM'e okuyacak olmasıdır, dolayısıyla büyük dosyalar üzerinde donacaktır.
MarSoft

5

takip etmek işe yaramaz

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

bu çalışmalı

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

3

Geçici bir dosya oluşturmadan ve! = (Gawk 4.1.0) sürümüyle kullanılabilen yalnızca bir awk çözümü istiyorsanız:

awk '{a[b++]=$0} END {for(c=0;c<=b;c++)print a[c]>ARGV[1]}' file

4
Ancak bu, tüm dosyayı belleğe alıyor mu? 20 GB'lık bir dosya düşünün.
Amit Naidu

0

Tee kullanma

 awk '{awk code}' file | tee file

teeKomut sürüyorsunuz ve sonra infaz awkkomut dolayı bitti |.


5
Bu yanlış. İki komut paralel olarak yürütülür ve veriler hemen boru boyunca aktarılır. Arabellekten daha büyük herhangi bir dosya (benim makinemde 8192 bayt) kesilecek ve veri kaybedeceksiniz.
tripflag
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.