web-dev-qa-db-ja.com

Ctrl-Cをawkスクリプトにトラップする

私は信じている Ctrl-C bashスクリプトにトラップされる可能性があります。そのイベントを処理するためにAwkスクリプト内にトラップすることも可能ですか?

たとえば、処理を中止するが、単に黙って終了するのではなく、すでに処理されたものの結果を出力する場合はどうでしょうか。

8

私はそれをサポートしている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;

もう1つの方法は、データのフィード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+Cawkでは、次のことができます。

(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}'
)
10