如何在Perl脚本中从Emacs中获取SIGINT信号



我正在尝试使用 Perl system调用在终端窗口中将 Emacs 作为前台进程运行。我想在终端窗口中按 CTRL-C 时终止 Emacs 和 Perl 脚本。但是,只有 Emacs 命令会终止。下面是一个示例脚本test.pl

#! /usr/bin/env perl
use strict;
use warnings;
my $cmd = shift;
for ( my $i = 1; $i <= 3; $i ++) {
    my $res = system ($cmd);
    if ( $res == -1 ) {
        die "Failed to execute '$cmd': $!n";
    }
    my $signal = ($? & 127);
    my $exit_code = ($? >> 8);
    print "exit_code = $exit_code, signal = $signaln";
    if ( $signal ) {
        die "Command '$cmd' died with signal $signaln";
    }
}

的输出

$ test.pl 'emacs file.txt'

是(按CTRL-C三次后):

^Cexit_code = 0,信号 = 0
^Cexit_code = 0,信号 = 0
^Cexit_code = 0,信号 = 0

所以Emacs被终止了,但Perl脚本继续运行。但是,如果我运行

$ test.pl 'sleep 10'

我得到输出:

^Cexit_code = 0,信号 = 2
命令"睡眠 10"因信号 2 而死亡

因此,如果我运行sleep 10而不是emacs file.txt它工作正常。

您的代码错误地假设您将执行的命令将捕获 INT 信号,然后使用 (128 * "退出状态") + signum 的约定设置其退出代码。

对于

睡眠来说是正确的,但对于许多其他程序来说是错误的。

但是,您可以以适用于任何所需命令的方式构建包装器。 这将是一个仅用于处理 Control-C 的 emacs 包装器:

#!/bin/bash -e
trap "exit 130" INT
emacs "$@"

只需将其放在您的路径中并在perl代码中执行即可,而不是emacs。 将其扩展到其他信号是微不足道的。 虽然它对我有用,但似乎这个版本对你有用:

#!/bin/bash -e
emacs "$@"

另一种解决方案是使用 perl 工具来处理子进程

您可以使用

IPC::Open2将 Emacs 作为子进程运行。然后使用 Perl 脚本中的waitpid来等待孩子。如果Perl脚本(父脚本)收到SIGINT信号,子脚本也将收到SIGINT信号。因此,以下内容似乎有效:

use strict;
use warnings;
use IPC::Open2;
my $cmd = shift;
$SIG{INT} = sub { die "Parent got SIGINTn" };
for ( my $i = 1; $i <= 3; $i ++) {
    print "i = $in";
    my ($chld_out, $chld_in);
    my $pid = open2($chld_out, $chld_in, $cmd);
    waitpid($pid, 0);
}

引用:

  • 当发送到包含子项的 perl 脚本时,SIGINT (^C) 会发生什么?
  • Perl fork() exec() , 子进程变得疯狂

最新更新