8

I believe Ctrl-C can be trapped in bash scripts. Is it also possible to trap it inside an Awk script in order to handle that event?

For example, for aborting processing, but printing the results of what has been processed already, instead of just silenty quitting?

9

I'm not aware of any awk implementation that has support for that. You could write an extension for gawk for that, but here, I'd rather switch to another language.

perl makes it easy to convert awk scripts with its a2p script.

For instance, if you have an awk script like:

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

a2p on it will give you something like:

#!/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;
}

Which you can edit to add your signal handling (and remove that processing of var=value arguments which we don't want here, and the part intended for systems that don't support #!):

#!/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;

Another alternative could be to interrupt the feeding of data to awk, and have awk ignore the SIGINT, like instead of:

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

do:

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

Ctrl+C will then kill cat but not awk. awk will still keep on processing remaining input still in the pipe.

To detect the Ctrl+C in awk, you could do:

(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}'
)
  • I adopted your final example and it works great! Thanks. – Eugene Beresovsky Feb 10 '16 at 6:51

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.