stupendo sul posto e stdout


10

È possibile usare gawkl' -i inplaceopzione e anche stampare gli oggetti stdout?

Ad esempio, se volessi aggiornare un file, e se ci fossero delle modifiche, stampa il nome del file e le righe cambiate stderrpotrei fare qualcosa di simile

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

ma c'è un modo di usare stdoutinvece, o un modo più pulito per stampare quel blocco sul flusso alternativo?


2
In questo caso particolare potresti voler eseguire qualcosa del genere in find -type f -name 'myfiles' -exec grep -q 'pattern' {} \; -print -exec gawk -i inplace '{do_your_sub_and_print_to_dev/stderr_too}' {} \;modo da utilizzare awk solo per modificare i file che contengono effettivamente linee che corrispondono a quel modello.
don_crissti,

@don_crissti Spesso dimentico quanto greppuò essere più veloce . Il mio primo istinto è quello di evitare di dover "elaborare" il file due volte, ma non sarei affatto sorpreso se fosse comunque più veloce. Ciò dimostra semplicemente perché posso fidarmi del mio istinto nei compiti di profilazione
Eric Renouf, l'

1
Sì, è abbastanza veloce e tieni presente che: 1) se non c'è corrispondenza, elabori il file una sola volta (la parte con -print -exec gawknon viene più eseguita) e 2) si fermerà alla prima corrispondenza quindi a meno che la prima non sia sulla ultima riga non stai ancora elaborando l'intero file due volte (è più simile a 1.X volte). Inoltre, se gawk -i inplacefunziona così sed -i, modificherà comunque il file sul posto, ovvero aggiornando timestamp, inode ecc. Anche se non c'era nulla da modificare ...
don_crissti

Risposte:


13

Dovresti usare /dev/stderro /dev/fd/2invece di /proc/self/fd/2. gawkgestisce /dev/fd/xe /dev/stderrda solo (indipendentemente dal fatto che il sistema abbia quei file o meno).

Quando fai un:

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

gawkfa un write(2, "x\n"), mentre quando lo fai:

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

dal momento che non tratta in modo /proc/self/fd/xspeciale, fa un:

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

Il primo /proc/self/fdè specifico di Linux e su Linux sono problematici. Le due versioni precedenti non sono equivalenti quando stderr si trova in un file normale o di altro tipo o in un socket (per il quale quest'ultimo fallirebbe) (per non parlare del fatto che spreca un descrittore di file).

Detto questo, se devi scrivere sullo stdout originale, devi salvarlo in un altro file come:

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

gawkreindirizza stdout con sul posto al file. È necessario perché, ad esempio, vorresti:

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

per salvare l' unameoutput nel file file.


2

Solo per divertimento, un approccio alternativo utilizzando solo POSIX dispone di find, sh, grepe (in particolare) 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 {} +

(Tutte le interruzioni di riga nel comando precedente sono opzionali; possono essere condensate in una riga.)

O, probabilmente, più leggibile:

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

:)


(Questo comando non è stato testato; le modifiche sono benvenute se ho fatto delle sciocchezze.)

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.