admin管理员组

文章数量:1422029

Edit: thank you guys for helping me, the code I used to solve the problem is at the end of the post (*), and for the executed command output "if we consider byeprogram produce some output to stdout" I think to redirect it to a pipe, but it did not work well

I am working on project, and I faced an a issue, the issue is that I cannot catch the exit code "status code" of process that worked in background, take this program as an example, that exits with 99 if it received a sigint, the code:

#include <signal.h>
#include <stdlib.h>
#include <unistd.h>

void bye(){
// exit with code 99 if sigint was received
    exit(99);
}
int main(int argc,char** argv){
    signal(SIGINT, bye);
    while(1){
        sleep(1);
    }
    return 0;
}

then I compiled it using gcc example.c -o byeprogram

in the same directory, I have my bash script:


set -x

__do_before_wait(){
    ##some commands
    return 0
}


__do_after_trap(){
    ##some commands
    return 0
}

runbg() {
    local __start_time __finish_time __run_time
    __start_time=$(date +%s.%N)

    # Run the command in the background
    ($@) &
    __pid=$!

    trap '
        kill -2 $__pid
        echo $?
        __finish_time=$(date +%s.%N)
        __run_time=$(echo "$__finish_time - $__start_time" | bc -l)
        echo "$__run_time"
        __do_after_trap || exit 2
    ' SIGINT
    __do_before_wait || exit 1
    wait $__pid
    ## now if you press ctrl+c, it will execute the commands i wrote in trap
}

out=`runbg  /path/to/byeprogram`

my problem is I want to catch or print the code 99, but I cannot, I tried to execute the byeprogram from the terminal, and type ctrl+c, and it return 99, how to catch the 99 status code??

*solution:


runbg() {
# print status_code,run_time
# to get the status code use ( | gawk -F, {print $1})
# to get the run time use ( | gawk -F, {print $2})

    __trap_code(){
        kill -2 $__pid
        wait $__pid
        __status_code=$?
        __finish_time=$(date +%s.%N)
        __run_time=$(echo "$__finish_time - $__start_time" | bc -l)
        echo "$__status_code,$__run_time"
        __do_after_trap
        exit 0
    }
    local __start_time __finish_time __run_time
    __start_time=$(date +%s.%N)
    ($@) &
    local __pid=$!
    trap __trap_code SIGINT
    __do_before_wait
    wait $pid
    __status_code=$?
    __finish_time=$(date +%s.%N)
    __run_time=$(echo "$__finish_time - $__start_time" | bc -l)
    echo "$__status_code,$__run_time"
}

Edit: thank you guys for helping me, the code I used to solve the problem is at the end of the post (*), and for the executed command output "if we consider byeprogram produce some output to stdout" I think to redirect it to a pipe, but it did not work well

I am working on project, and I faced an a issue, the issue is that I cannot catch the exit code "status code" of process that worked in background, take this program as an example, that exits with 99 if it received a sigint, the code:

#include <signal.h>
#include <stdlib.h>
#include <unistd.h>

void bye(){
// exit with code 99 if sigint was received
    exit(99);
}
int main(int argc,char** argv){
    signal(SIGINT, bye);
    while(1){
        sleep(1);
    }
    return 0;
}

then I compiled it using gcc example.c -o byeprogram

in the same directory, I have my bash script:


set -x

__do_before_wait(){
    ##some commands
    return 0
}


__do_after_trap(){
    ##some commands
    return 0
}

runbg() {
    local __start_time __finish_time __run_time
    __start_time=$(date +%s.%N)

    # Run the command in the background
    ($@) &
    __pid=$!

    trap '
        kill -2 $__pid
        echo $?
        __finish_time=$(date +%s.%N)
        __run_time=$(echo "$__finish_time - $__start_time" | bc -l)
        echo "$__run_time"
        __do_after_trap || exit 2
    ' SIGINT
    __do_before_wait || exit 1
    wait $__pid
    ## now if you press ctrl+c, it will execute the commands i wrote in trap
}

out=`runbg  /path/to/byeprogram`

my problem is I want to catch or print the code 99, but I cannot, I tried to execute the byeprogram from the terminal, and type ctrl+c, and it return 99, how to catch the 99 status code??

*solution:


runbg() {
# print status_code,run_time
# to get the status code use ( | gawk -F, {print $1})
# to get the run time use ( | gawk -F, {print $2})

    __trap_code(){
        kill -2 $__pid
        wait $__pid
        __status_code=$?
        __finish_time=$(date +%s.%N)
        __run_time=$(echo "$__finish_time - $__start_time" | bc -l)
        echo "$__status_code,$__run_time"
        __do_after_trap
        exit 0
    }
    local __start_time __finish_time __run_time
    __start_time=$(date +%s.%N)
    ($@) &
    local __pid=$!
    trap __trap_code SIGINT
    __do_before_wait
    wait $pid
    __status_code=$?
    __finish_time=$(date +%s.%N)
    __run_time=$(echo "$__finish_time - $__start_time" | bc -l)
    echo "$__status_code,$__run_time"
}

Share Improve this question edited Jan 18 at 19:43 Amr Alasmer asked Jan 17 at 15:24 Amr AlasmerAmr Alasmer 511 silver badge4 bronze badges 2
  • If you put echo $? after the wait line it should print 99. – Barmar Commented Jan 17 at 17:13
  • See the wait documentation: gnu./software/bash/manual/html_node/… – Barmar Commented Jan 17 at 17:14
Add a comment  | 

1 Answer 1

Reset to default 1
  1. When you press CTRL-C, the command wait $__pid will also be interrupted and return 130.

    $ sleep 999 &
    [1] 3222
    $ wait $!
    ^C         <-- Press ctrl-c
    $ echo $?
    130
    
  2. When you press CTRL-C, the assignment statement out=`runbg /path/to/byeprogram` will also be interrupted and return 130.

     $ ( trap 'exit 99' INT; sleep 999 )
     ^C
     $ echo $?
     99
     $ out=$( trap 'exit 99' INT; sleep 999 )
     ^C    <-- I'm not quite sure how SIGINT is interacting with the out=
           <-- assignment and the $() subshell. Need to go deep into Bash's
           <-- code to find out. At least the status code is not 99.
     $ echo $?
     130
    

The following foo.sh can get the 99 code (This might not be the solution to your real problem. Just show how it behaves.):

# File: foo.sh

__do_before_wait(){
    ##some commands
    return 0
}


__do_after_trap(){
    ##some commands
    return 0
}

runbg() {
    local __start_time __finish_time __run_time
    __start_time=$(date +%s.%N)

    # Run the command in the background
    ($@) &
    __pid=$!

    trap '
    #   kill -2 $__pid
        __finish_time=$(date +%s.%N)
        __run_time=$(echo "$__finish_time - $__start_time" | bc -l)
        echo
        echo "RUN TIME: $__run_time"
        __do_after_trap || exit 2
    ' SIGINT

    sleep 9999

    __do_before_wait || exit 1
    wait $__pid
}

runbg ~/tmp/byeprogram
echo "RET CODE: $?"

I added a sleep 9999 before wait. When you press CTRL-C, it'll interrup this sleep command so wait will not be impacted and it can still get the job's status code as expected.

Note that I commented out kill -2 $__pid. It is not necessary here because when your press CTRL-C, the SIGINT signal will also be passed to byeprogram and kill it.

Example output:

$ bash --version
GNU bash, version 5.2.15(1)-release (x86_64-pc-linux-gnu)
$ bash foo.sh
^C
RUN TIME: 3.508632016
RET CODE: 99

本文标签: signalshow to catch status code of killed process by bash scriptStack Overflow