Ловушка Ctrl-C в скрипте awk

8

Я верю Ctrl- Cможно поймать в ловушку bash-скриптов. Возможно ли перехватить его внутри скрипта Awk для обработки этого события?

Например, для прерывания обработки, но для печати результатов того, что уже было обработано, а не просто для тихого выхода?

Евгений Бересовский
источник
вам придется обернуть его в сценарий оболочки или написать расширение для awk AFAIK.
jai_s
1
Да, начните с чтения , что: gnu.org/software/gawk/manual/html_node/...
jlliagre
Пример: github.com/takubo/awk-posix-signal
cuonglm

Ответы:

10

Я не знаю ни о какой awkреализации, которая имеет поддержку для этого. Вы можете написать расширение для gawkэтого , но здесь я бы лучше переключился на другой язык.

perlпозволяет легко конвертировать awkскрипты с его a2pскриптом.

Например, если у вас есть такой awkскрипт:

{count[$0]++}
END {
  for (i in count) printf "%5d %s\n", count[i], i
}

a2p на это даст вам что-то вроде:

#!/usr/bin/perl
eval 'exec /usr/bin/perl -S $0 ${1+"$@"}'
    if $running_under_some_shell;
                        # this emulates #! processing on NIH machines.
                        # (remove #! line above if indigestible)

eval '$'.$1.'$2;' while $ARGV[0] =~ /^([A-Za-z_0-9]+=)(.*)/ && shift;
                        # process any FOO=bar switches

while (<>) {
    chomp;      # strip record separator
    $count{$_}++;
}

foreach $i (keys %count) {
    printf "%5d %s\n", $count{$i}, $i;
}

То, что вы можете отредактировать, чтобы добавить свою обработку сигналов (и удалить ту обработку var=valueаргументов, которую мы здесь не хотим, и часть, предназначенную для систем, которые не поддерживают #!):

#!/usr/bin/perl

sub report {
  foreach $i (keys %count) {
      printf "%5d %s\n", $count{$i}, $i;
  }
}

$SIG{INT} = sub {
  print STDERR "Interrupted\n";
  report;
  $SIG{INT} = 'DEFAULT';
  kill('INT', $$); # report dying of SIGINT.
};

while (<>) {
    chomp;      # strip record separator
    $count{$_}++;
}

report;

Другой альтернативой может быть , чтобы прервать подачу данных к awk, и имеют awkигнорировать SIGINT, как вместо того , чтобы :

awk '{count[$0]++};END{for (i in count) printf "%5d %s\n", count[i], i}' file

делать:

cat file | (
  trap '' INT
  awk '{count[$0]++};END{for (i in count) printf "%5d %s\n", count[i], i}'
)

Ctrl+Cпотом убью catно не awk. awkбудет продолжать обрабатывать оставшиеся входные данные, все еще находящиеся в канале.

Для обнаружения Ctrl+Cин awk, вы можете сделать:

(cat file && echo cat terminated normally) | (
  trap '' INT
  awk '{count[$0]++}
       END{
         if ($0 == "cat terminated normally") delete count[$0]
         else print "Interrupted"
         for (i in count) printf "%5d %s\n", count[i], i}'
)
Стефан Шазелас
источник
Я принял ваш последний пример, и он прекрасно работает! Спасибо.
Евгений Бересовский