melongo inplace dan stdout

10

Apakah mungkin untuk menggunakan gawk's -i inplacepilihan dan juga mencetak hal yang stdout?

Misalnya, jika saya ingin memperbarui file, dan jika ada perubahan, cetak nama file dan baris yang diubah ke stderrsaya bisa melakukan sesuatu seperti

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;}' {} +

tetapi apakah ada cara untuk menggunakannya stdout, atau cara yang lebih bersih untuk mencetak blok itu ke aliran alternatif?

Eric Renouf
sumber
2
Dalam kasus khusus ini Anda mungkin ingin menjalankan sesuatu seperti find -type f -name 'myfiles' -exec grep -q 'pattern' {} \; -print -exec gawk -i inplace '{do_your_sub_and_print_to_dev/stderr_too}' {} \;itu Anda hanya akan menggunakan awk untuk mengedit file yang benar-benar berisi garis yang cocok dengan pola itu.
don_crissti
@don_crissti Saya sering lupa seberapa cepat grepbisa. Naluri pertama saya adalah untuk menghindari "proses" file dua kali, tetapi saya tidak akan terkejut sama sekali jika memang lebih cepat. Itu hanya untuk menunjukkan mengapa saya bisa memercayai nyali saya pada tugas pembuatan profil
Eric Renouf
1
Ya, ini cukup cepat dan perlu diingat bahwa: 1) jika tidak ada kecocokan, Anda hanya memproses file sekali (bagian dengan -print -exec gawktidak dieksekusi lagi) dan 2) itu akan berhenti pada pertandingan pertama jadi kecuali pertandingan pertama ada di baris terakhir Anda masih belum memproses seluruh file dua kali (ini lebih seperti 1,X kali). Juga, jika gawk -i inplaceberfungsi seperti sed -iitu akan mengedit file di tempat - yaitu memperbarui cap waktu, inode dll bahkan jika tidak ada yang perlu diedit ...
don_crissti

Jawaban:

13

Anda harus menggunakan /dev/stderratau /dev/fd/2bukannya /proc/self/fd/2. gawkmenangani /dev/fd/xdan /dev/stderrdengan sendirinya (terlepas dari apakah sistem memiliki file-file itu atau tidak).

Ketika Anda melakukan:

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

gawktidak write(2, "x\n"), sementara ketika Anda melakukannya:

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

karena tidak memperlakukan /proc/self/fd/xsecara khusus, ia melakukan:

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

Pertama /proc/self/fdadalah Linux khusus dan di Linux mereka bermasalah. Dua versi di atas tidak setara ketika stderr adalah untuk file biasa atau yang dapat dicari lainnya atau ke soket (untuk yang terakhir akan gagal) (belum lagi bahwa itu membuang deskriptor file).

Yang sedang berkata, jika Anda perlu menulis ke stdout asli, Anda perlu menyimpannya di fd lain seperti:

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

gawkmelakukan redirect stdout dengan di tempat ke file. Ini diperlukan karena misalnya, Anda ingin:

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

untuk menyimpan unameoutput ke dalam file.

Stéphane Chazelas
sumber
2

Just for fun, pendekatan alternatif hanya menggunakan POSIX fitur dari find, sh, grepdan (terutama) 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 {} +

(Semua jeda baris dalam perintah di atas adalah opsional; dapat disingkat menjadi satu-liner.)

Atau, bisa dibilang lebih terbaca:

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 {} +

:)


(Perintah ini belum diuji; suntingan diterima jika saya membuat kesalahan.)

Wildcard
sumber