【问题标题】:How to pick up SIGINT signal from Emacs in Perl script?如何在 Perl 脚本中从 Emacs 中获取 SIGINT 信号?
【发布时间】:2015-03-11 14:24:59
【问题描述】:

我正在尝试使用 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 = $signal\n";
    if ( $signal ) {
        die "Command '$cmd' died with signal $signal\n";
    }
}

的输出
$ 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
命令 'sleep 10' 因信号 2 而死

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

【问题讨论】:

  • 你运行/usr/bin/emacs,还是一些包装器?什么操作系统?
  • @choroba 我正在使用 Ubuntu 14.04 并运行命令 /opt/emacs24.4/bin/emacs

标签: perl emacs


【解决方案1】:

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

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

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

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

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

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

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

【讨论】:

  • 感谢@juanleon 的回复。但它还没有工作,当我运行 test.pl 'wrapper.sh file.txt' 我得到 ^Cexit_code = 130, signal = 0 所以它似乎没有向父 Perl 脚本发送 SIGINT ..
  • 很奇怪。这对我来说可以。 $? 对你有什么价值? 130 没问题,但既然你做了my $signal = ($? &amp; 127); 和my $exit_code = ($? &gt;&gt; 8);,$signal 应该是 2 而 $exit_code 应该是 0。你修改了那个代码吗?请注意,没有人会将 SIGINT 发送到父 perl 脚本; perl 脚本将 SIGINT 中继到正在执行的命令(当您按下 Control-C 时),并且当命令因任何原因停止时,perl 脚本重新获得控制权。
  • 好的,我明白了.. 不,我没有修改代码,我得到$? = 33280
  • 可能与 Perl 版本有关?我正在使用 Perl v5.18.2.. 你运行的是什么版本的 Perl?
  • v5.14.2。我猜在你的情况下 perl 正在设置 $ 的值?以与我不同的方式(在本地我得到与我在命令中设置的相同的退出代码)。我的 perl 黑客时代已经一去不复返了,而且大部分时间都被遗忘了,所以我不知道为什么。无论如何,您似乎没有获得良好的一致性(睡眠 vs emacs vs wrapper)。
【解决方案2】:

您可以使用IPC::Open2 将 Emacs 作为子进程运行。然后使用 Perl 脚本中的waitpid 等待子进程。如果 Perl 脚本(父级)收到一个 SIGINT 信号,那么子级也将收到一个 SIGINT 信号。所以以下似乎有效:

use strict;
use warnings;
use IPC::Open2;

my $cmd = shift;

$SIG{INT} = sub { die "Parent got SIGINT\n" };
for ( my $i = 1; $i <= 3; $i ++) {
    print "i = $i\n";
    my ($chld_out, $chld_in);
    my $pid = open2($chld_out, $chld_in, $cmd);
    waitpid($pid, 0);
}

参考资料:

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-14
    • 2010-10-22
    • 2010-09-26
    • 1970-01-01
    相关资源
    最近更新 更多