Displaying or redirecting a shell's job control messages

主宰稳场 提交于 2019-12-12 11:11:38

问题


TL;DR

All job control / crash messages are hidden when they occur within a function. I go into more detail below, but @Barmar has pointed out that this issue can be reproduced by running a crashing binary inside of a function, e.g:

crun() { 
  /tmp/faulty $1 $2 $3
}

I've defined a function in my .zshrc to compile & run source code with the function below:

crun() {
    local file=$1
    shift
    local exepath="$(mktemp)"

    if [[ $file =~ "\.c$" ]]; then
        gcc -g -Wall $file -o $exepath || return $?
    else
        echo "no filetype detected"
        return 126
    fi

    $exepath "$@"
}

Which can be called in this fashion:

% crun source.cc arg_1 arg_2

This works for normal programs, but has the problem that the shell's job control messages, such as those generated from a segfault, do not appear.

As an example:

% echo 'int main=0;' >> /tmp/faulty.c # a crashing c program
% crun faulty.c
% # no output generated

Whereas the equivalent interactive commands would generate this:

% g++ faulty.c -o /tmp/faulty && /tmp/faulty
[1] 2894 segmentation fault (core dumped) # 🢀 zsh's job control output for SIGSEGV

Is there any way to display these messages for a crashing executable whose path is dynamically calculated? Ideally without writing your own trap/signal handlers + exec, using sh -c "$exepath $@", or writing a totally new system(3) wrapper entirely)


回答1:


You can get zsh to print the segmentation fault message from the job if you start it as a background job and then immediately bring it to the foreground.

"$exepath" "$@" &
fg

This will cause zsh to print out messages for signals on the job started for $exepath.

The downside is that you will get a little bit more than you bargained for:

% crun faulty.c
faulty.c:1:5: warning: ‘main’ is usually a function [-Wmain]
 int main=0;
     ^~~~
[2] 2080
[2]  - running    "$exepath" "$@"
zsh: segmentation fault (core dumped)  "$exepath" "$@"

But as shown, you will get the segfault messages printed in the terminal.

Because the messages are printed by the interactive shell, not the failing process, the job messages won't get redirected should you try to redirect stdout or stderr.

So on the one hand, should you try to take useful output out of your running process and redirect it somewhere else, you don't need to worry about the job messages getting in the way. But this also means you won't get the segfault message should you try to redirect it by redirecting stderr.

Here's a demonstration of this effect, with line breaks added in-between commands for clarity:

% crun good.c > test
[2] 2071
[2]  - running    "$exepath" "$@"

% cat test
Hello, world!

% crun faulty.c 2>test
[2] 2092
[2]  - running    "$exepath" "$@"
zsh: segmentation fault (core dumped)  "$exepath" "$@"

% cat test
faulty.c:1:5: warning: ‘main’ is usually a function [-Wmain]
 int main=0;
     ^~~~

For more information, see zsh's documentation on jobs and signals. You can also poke around the C file where the magic happens.



来源:https://stackoverflow.com/questions/45023243/displaying-or-redirecting-a-shells-job-control-messages

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!