gawk inplace ve stdout


10

gawk'S -i inplaceseçeneğini kullanmak ve bir şeyler yazdırmak mümkün stdoutmü?

Örneğin, bir dosyayı güncellemek istersem ve herhangi bir değişiklik olursa dosyanın adını ve değiştirilen satırları yazdırır stderrgibi bir şey yapabilirim

find -type f -name 'myfiles' -exec gawk -i inplace '{if(gsub(/pat/, "repl")) { print FILENAME > "/proc/self/fd/2" ; print > "/proc/self/fd/2"; } print;}' {} +

ancak stdoutbunun yerine kullanmanın bir yolu veya bu bloğu alternatif akışa yazdırmanın daha temiz bir yolu var mı?


2
Bu özel durumda, böyle bir şey çalıştırmak isteyebilirsiniz find -type f -name 'myfiles' -exec grep -q 'pattern' {} \; -print -exec gawk -i inplace '{do_your_sub_and_print_to_dev/stderr_too}' {} \;, sadece bu kalıpla eşleşen satırları içeren dosyaları düzenlemek için sadece awk kullanırsınız.
don_crissti

@don_crissti Sık sık ne kadar hızlı grepolabileceğini unuturum . İlk içgüdüm dosyayı iki kez "işlemekten" kaçınmaktır, ancak yine de daha hızlı olsaydı hiç şaşırmam. Sadece profilleme görevlerindeki bağırsağıma neden güvenebileceğimi gösteriyor
Eric Renouf

1
Evet, oldukça hızlı ve şunu unutmayın: 1) eşleşme yoksa, dosyayı yalnızca bir kez işlersiniz (artık bölüm -print -exec gawkyürütülmez) ve 2) 1. maçta durur, böylece 1. maç son satır hala tüm dosyayı iki kez işlemiyorsunuz (daha çok 1.X gibi). Ayrıca, eğer gawk -i inplaceböyle çalışırsa sed -iyine de dosyayı yerinde düzenleyecektir - yani düzenlemek için hiçbir şey olmasa bile zaman damgalarını, inode vb güncelleme ...
don_crissti

Yanıtlar:


13

Kullanmalı /dev/stderrveya /dev/fd/2yerine kullanmalısınız /proc/self/fd/2. gawkkolları /dev/fd/xve /dev/stderrkendisi tarafından (bakılmaksızın sistem bu dosyaları vardır olsa da olmasa da).

Şunları yaptığınızda:

print "x" > "/dev/fd/2"

gawkBir yapar write(2, "x\n")bunu yaptığında ise,:

print "x" > "/proc/self/fd/2"

o tedavi olmadığından /proc/self/fd/xözel olarak, bir yapar:

fd = open("/proc/self/fd/2", O_WRONLY|O_CREAT|O_TRUNC);
write(fd, "x\n");

Birincisi /proc/self/fdLinux'a özgü ve Linux'ta sorunlu. Yukarıdaki iki sürüm, stderr normal veya başka bir aranabilir dosyaya veya bir sokete (ikincisinin başarısız olacağı durumdaysa) eşdeğer değildir (dosya tanımlayıcısını boşa harcadığından bahsetmiyorum).

Bununla birlikte, orijinal stdout'a yazmanız gerekiyorsa, aşağıdaki gibi başka bir fd'ye kaydetmeniz gerekir:

gawk -i inplace '{
   print "goes into the-file"
   print "to stdout" > "/dev/fd/3"}' the-file 3>&1

gawkstdout'u yerinde yerinde yeniden yönlendirir. Gerekli, çünkü örneğin:

awk -i inplace '{system("uname")}' file

unameçıktıyı saklamak için file.


2

Sadece eğlence için, sadece POSIX kullanarak alternatif bir yaklaşım özelliklerinin find, sh, grepve (en önemlisi) ex:

find . -type f -name 'myfiles' -exec sh -c '
  for f do grep -q "pat" "$f" &&
    { printf "%s\n" "$f";
      printf "%s\n" "%s/pat/repl/g" x | ex "$f";
  }; done' find-sh {} +

(Yukarıdaki komuttaki tüm satır sonları isteğe bağlıdır; bir astarla yoğunlaştırılabilir.)

Veya tartışmasız daha okunaklı:

find . -type f -name 'myfiles' -exec sh -c '
  for f
  do
    if grep -q "pat" "$f"; then
      printf "%s\n" "$f"
      printf "%s\n" "%s/pat/repl/g" x | ex "$f"
    fi
  done' find-sh {} +

:)


(Bu komut test edilmemiştir; herhangi bir goof yaparsam düzenlemeler hoş geldiniz.)

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.