发送SIGINT

时间:2017-04-21 17:42:54

标签: bash

我终于厌倦了makefile并编写了自己的bash脚本来进行编译。我写了整篇文章,它很有效,但由于某些原因,当我尝试用ctrl-c取消它时,它会冻结。这是脚本:

#!/bin/bash

# Just to see if the script even sees the SIGINT
trap caught SIGINT
caught() { echo "hi"; }

compile() {
    cpp=$(echo "$1" | sed -e 's/$/.cpp/' -e 's/^/src\//')
    o=$(echo "$1" | sed -e 's/$/.o/' -e "s/^/$build_dir\//")
    echo "$compile -c $cpp -o $o"
    eval "$compile -c $cpp -o $o"
    return $?
}

# I know this isn't normal, but I hate it when I forget to include something
# in the header and it fails way down the line
compile_h() {
    h=$(echo "$1" | sed -e 's/$/.h/' -e 's/^/src\//')
    o=$(echo "$1" | sed -e 's/$/.o/' -e "s/^/$build_dir\/headers\//")
    echo "$compile -c $h -o /dev/null"
    eval "$compile -x c++ -c $h -o $o"
    if [ $? -ne 0 ]; then
        return 1
    fi
    rm "$o"
    return 0
}

build_type=$(awk 'NR==1' .build_options)
compile_command_debug=$(awk 'NR==2' .build_options)
link_command_debug=$(awk 'NR==3' .build_options)
compile_command_production=$(awk 'NR==4' .build_options)
link_command_production=$(awk 'NR==5' .build_options)
libraries=$(awk 'NR==6' .build_options)

# Make options for this build
build_dir="build"
compile="$compile_command_debug"
link="$link_command_debug"
if [ "$build_type" == "production" ]; then
    build_dir="buildp"
    compile="$compile_command_production"
    link="$link_command_production"
fi
# These options need to be changeable later
output="game"
job_number=5

# There are more options, but they aren't important for this problem
while [ "$1" != "" ]; do
    if [ "$1" == "clean" ]; then
        rm -r $build_dir/*
    fi
    shift
done

# Get filenames
cpps=$(find src -name *.cpp | sed -e 's/src\///' -e 's/.cpp//' | sort)
hs=$(find src -name *.h | sed -e 's/src\///' -e 's/.h//' | sort)

# Ensure that all directories exist
directories=$(find src -type d | tail --lines=+2 | sed 's/src\///' | sort)
if [ ! -d "$build_dir/headers" ]; then
    mkdir "$build_dir/headers"
fi
for dir in $directories; do
    if [ ! -d "$build_dir/$dir" ]; then
        mkdir "$build_dir/$dir"
    fi
    if [ ! -d "$build_dir/headers/$dir" ]; then
        mkdir "$build_dir/headers/$dir"
    fi
done

all_o="" # To be used for linking
# Determine what files need to be compiled
cpp_needed=""
h_needed=""
link_needed=false
# Check cpp files
for cpp_base in $cpps; do
    o=$(echo "$cpp_base" | sed -e 's/$/.o/' -e "s/^/$build_dir\//")
    all_o="$all_o $o"
    d_file=$(echo "$cpp_base" | sed -e 's/$/.d/' -e "s/^/$build_dir\//")
    if [ -f "$d_file" ]; then
        d=$(<"$d_file")
        d=$(echo "$d" | tr " " "\n" | tail --lines=+2 | grep "s")
        if [ "$link_needed" = false ]; then
            if [ "$o" -nt "$output" ]; then
                link_needed=true
            fi
        fi
        for dep in $d; do
            if [ "$dep" -nt "$o" ]; then
                if [ "$cpp_needed" == "" ]; then cpp_needed="$cpp_base"
                else cpp_needed="$cpp_needed $cpp_base"
                fi
                link_needed=true
                break
            fi
        done
    else
        if [ "$cpp_needed" == "" ]; then cpp_needed="$cpp_base"
        else cpp_needed="$cpp_needed $cpp_base"
        fi
        link_needed=true
    fi
done
# Check h files
for h_base in $hs; do
    d_file=$(echo "$h_base" | sed -e 's/$/.d/' -e "s/^/$build_dir\/headers\//")
    if [ -f "$d_file" ]; then
        d=$(<"$d_file")
        d=$(echo "$d" | tr " " "\n" | tail --lines=+2 | grep "s")
        for dep in $d; do
            if [ "$dep" -nt "$d_file" ]; then
                if [ "$h_needed" == "" ]; then h_needed="$h_base"
                else h_needed="$h_needed $h_base"
                fi
                break
            fi
        done
    else
        if [ "$h_needed" == "" ]; then h_needed="$h_base"
        else h_needed="$h_needed $h_base"
        fi
    fi
done

# Compile
did_something=false
# Compile hs
while [ "$h_needed" != "" ]; do
    for index in $(seq 1 $job_number); do
        if [ "$h_needed" == "" ]; then break; fi
        if ! kill -0 ${pids[index]} 2>/dev/null; then
            new_file=$(echo "$h_needed" | awk '{print $1;}')
            if [ $(echo "$h_needed" | wc -w) -eq 1 ]; then h_needed=""
            else h_needed=$(echo "$h_needed" | cut -d " " -f2-)
            fi
            compile_h "$new_file" &
            pids[index]=$!
            did_something=true
        fi
    done
    wait -n
    if [ $? -ne 0 ]; then
        wait
        exit 1
    fi
done
while [ $(pgrep -c -P$$) -gt 0 ]; do
    wait -n
    if [ $? -ne 0 ]; then
        wait
        exit 1
    fi
done

# Compile cpps
while [ "$cpp_needed" != "" ]; do
    for index in $(seq 1 $job_number); do
        if [ "$cpp_needed" == "" ]; then break; fi
        if ! kill -0 ${pids[index]} 2>/dev/null; then
            new_file=$(echo "$cpp_needed" | awk '{print $1;}')
            if [ $(echo "$cpp_needed" | wc -w) -eq 1 ]; then cpp_needed=""
            else cpp_needed=$(echo "$cpp_needed" | cut -d " " -f2-)
            fi
            compile "$new_file" &
            pids[index]=$!
            did_something=true
        fi
    done
    wait -n
    if [ $? -ne 0 ]; then
        wait
        exit 1
    fi
done
while [ $(pgrep -c -P$$) -gt 0 ]; do
    wait -n
    if [ $? -ne 0 ]; then
        wait
        exit 1
    fi
done

# Compile program
if [ "$link_needed" = true ]; then
    echo "$link $all_o -o game $libraries"
    eval "$link $all_o -o game $libraries"
    did_something=true
fi
# Make a message if nothing compiled
if [ "$did_something" = false ]; then
    echo "Program is already compiled."
fi

通常效果很好。但是,有时候,当我尝试用ctrl-c取消它时,它就会冻结。通过一些调试,我发现当脚本没有设置新工作时,ctrl-c可以正常工作。但是当它正在设置一个新工作时,它会冻结脚本。它甚至不会捕获SIGINT(其中&#34;回声嗨&#34;事情是在顶部)。老实说,我不知道发生了什么。有人知道发生了什么吗?谢谢!

编辑:我意识到我应该提一下我用g ++来编译。

再次编辑:这是一个更加精简的脚本版本。如果你想测试它,你仍然需要设置一些文件来编译:

#!/bin/bash

# Just to see if the script even sees the SIGINT
trap caught SIGINT
caught() { echo "hi"; }

# I know this isn't normal, but I hate it when I forget to include something
# in the header and it fails way down the line
compile_h() {
    h=$(echo "$1" | sed -e 's/$/.h/' -e 's/^/src\//')
    o=$(echo "$1" | sed -e 's/$/.o/' -e "s/^/$build_dir\/headers\//")
    echo "$compile -c $h -o /dev/null"
    eval "$compile -x c++ -c $h -o $o"
    if [ $? -ne 0 ]; then
        return 1
    fi
    rm "$o"
    return 0
}

build_type="debug"
build_dir="build"
compile="g++"
job_number=5

# Get filenames
hs=$(find src -name *.h | sed -e 's/src\///' -e 's/.h//' | sort)
h_needed=$(echo $hs)

# Compile hs
while [ "$h_needed" != "" ]; do
    for index in $(seq 1 $job_number); do
        if [ "$h_needed" == "" ]; then break; fi
        if ! kill -0 ${pids[index]} 2>/dev/null; then
            new_file=$(echo "$h_needed" | awk '{print $1;}')
            if [ $(echo "$h_needed" | wc -w) -eq 1 ]; then h_needed=""
            else h_needed=$(echo "$h_needed" | cut -d " " -f2-)
            fi
            compile_h "$new_file" &
            pids[index]=$!
            did_something=true
        fi
    done
    wait -n
    if [ $? -ne 0 ]; then
        wait
        exit 1
    fi
done
while [ $(pgrep -c -P$$) -gt 0 ]; do
    wait -n
    if [ $? -ne 0 ]; then
        wait
        exit 1
    fi
done

1 个答案:

答案 0 :(得分:0)

您在脚本中运行的任何程序都可能会覆盖您的陷阱并设置自己的陷阱。例如,该陷阱可能由于某种原因导致当前正在运行的程序崩溃。发生这种情况时,请查看ps wafux中的流程树,找出最可能的罪魁祸首。例如,僵尸(Z)或不间断睡眠(D)进程状态(请参阅man ps)在进程无法到达任何位置时很常见。