гаук на місці та виступ


10

Чи можна використовувати gawk«s -i inplaceваріанту , а також друкувати речі stdout?

Наприклад, якщо я хотів оновити файл, і якщо є якісь зміни, надрукуйте ім'я файлу та змінені рядки, stderrя міг би зробити щось на кшталт

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

але чи є спосіб використовувати stdoutзамість цього чи більш чистий спосіб друкувати цей блок до альтернативного потоку?


2
У цьому конкретному випадку ви можете запустити щось подібне find -type f -name 'myfiles' -exec grep -q 'pattern' {} \; -print -exec gawk -i inplace '{do_your_sub_and_print_to_dev/stderr_too}' {} \;, ви будете використовувати лише awk для редагування файлів, які насправді містять рядки, що відповідають цьому шаблону.
don_crissti

@don_crissti Я часто забуваю, наскільки швидше grepможе бути. Мій перший інстинкт - уникнути необхідності "обробляти" файл двічі, але я би не здивувався, якщо все-таки дійсно швидше. Це просто показує, чому я можу довіряти моїй кишці в завданнях з профілювання
Ерік Реноф

1
Так, це досить швидко і майте на увазі, що: 1) якщо немає відповідності, ви обробляєте файл лише один раз (частина з -print -exec gawkне виконується більше), і 2) він зупиняється на 1-му поєдинку, тому, якщо 1-й збіг не буде останній рядок, ви все ще не обробляєте весь файл двічі (це більше як 1.X разів). Крім того, якщо gawk -i inplaceтакі роботи все одно sed -iредагуватимуть файл на місці - тобто оновлення часових міток, inode тощо, навіть якщо редагувати нічого не було ...
don_crissti

Відповіді:


13

Ви повинні використовувати /dev/stderrабо /dev/fd/2замість цього /proc/self/fd/2. gawkобробляє /dev/fd/xі /dev/stderrсам по собі (незалежно від того, система має ці файли чи ні).

Коли ви робите:

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

gawkробить write(2, "x\n"), поки ви робите:

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

оскільки не лікується /proc/self/fd/xспеціально, він робить:

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

По-перше /proc/self/fd, специфічно для Linux, а для Linux вони є проблематичними. Дві версії, наведені вище, не є еквівалентними, коли stderr є звичайним або іншим пошуковим файлом або сокетом (для якого останній не зможе) (не кажучи вже про те, що він марнує дескриптор файлу).

Однак, якщо вам потрібно написати оригінальний stdout, вам потрібно зберегти його в іншому FD, наприклад:

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

gawkробить stdout переадресації з місцем у файл. Це потрібно, тому що, наприклад, ви хочете:

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

для збереження unameвиводу в file.


2

Просто для задоволення, альтернативний підхід , який використовує тільки POSIX риси find, sh, grepі (найголовніше) 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 {} +

(Усі перерви рядків у вищевказаній команді необов’язкові; вони можуть бути зведені до однолінійки.)

Або, можливо, більш розбірливо:

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

:)


(Ця команда не перевірена; редагування вітається, якщо я зробив якісь глухи.)

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.