为什么我的POSIX shell脚本会退出?

时间:2018-02-01 14:38:37

标签: shell debugging sh posix

我没有关于shell脚本的专家,但是如果下面的脚本是使用exit选项启动的,或者没有它,我会尝试避免使用-1

./empire -1
One-time coin collecting!
mouse_click_coords(): Coordinates must be in pairs! Exit code = 14.

我没有看到错误的位置(?)换句话说,脚本工作在100%,直到我不记得我改变了什么;除了在处理第一个循环结束时意外退出(通过-1选项,或等待它,它都是相同的)。

整个剧本如下:

#!/bin/sh

is_number()
{
    # check if exactly one argument has been passed
    test "$#" -eq 1 || print_error_and_exit 4 "is_number(): There has not been passed exactly one argument!"

    # check if the argument is an integer
    test "$1" -eq "$1" 2>/dev/null
}

# ------------------------------------------------------------------------------

print_error_and_exit()
{
    # check if exactly two arguments have been passed
    test "$#" -eq 2 || print_error_and_exit 2 "print_error_and_exit(): There have not been passed exactly two arguments!"

    # check if the first argument is a number
    is_number "$1" || print_error_and_exit 3 "print_error_and_exit(): The argument #1 is not a number!"

    bold=$(tput bold)
    red=$(tput setaf 1)
    nocolor=$(tput sgr0)

    echo "$bold$red$2 Exit code = $1.$nocolor" >&2
    exit "$1"
}

# ------------------------------------------------------------------------------

check_for_prerequisite()
{
    # check if exactly one argument has been passed
    test "$#" -eq 1 || print_error_and_exit 1 "check_for_prerequisite(): There has not been passed exactly one argument!"

    # check if the argument is a program which is installed
    command -v "$1" > /dev/null 2>&1 || print_error_and_exit 127 "check_for_prerequisite(): I require $1 but it's not installed :-("
}

check_for_prerequisite "xdotool"
check_for_prerequisite "wmctrl"
check_for_prerequisite "shuf"
check_for_prerequisite "xdpyinfo"
check_for_prerequisite "awk"
check_for_prerequisite "printf"

# ------------------------------------------------------------------------------

print_usage_and_exit()
{
    # check if exactly one argument has been passed
    test "$#" -eq 1 || print_error_and_exit 1 "print_usage_and_exit(): There has not been passed exactly one argument!"

    # check if both of the arguments are numbers
    is_number "$1" || print_error_and_exit 16 "print_usage_and_exit(): The argument is not a number! Exit code expected."

    echo "Usage:   $0 [-1]"
    echo "         -1: One-time coin collect."
    echo "Default: Repeat coin collecting until interrupted."
    exit "$1"
}

# ------------------------------------------------------------------------------

no_repeat=0

while getopts ":1h" option
do
    case "$option" in
        1)
          no_repeat=1
          ;;
        h)
          print_usage_and_exit 0
          ;;
        *)
          print_usage_and_exit 1 >&2
          ;;
    esac
done

# ------------------------------------------------------------------------------

# global constants
window_name_chrome="Goodgame Empire - Google Chrome"
screen_resolution=$(xdpyinfo | awk '/dimensions:/ {print $2}')

# global variables
previous_rand=10
operation_add=1

# ------------------------------------------------------------------------------

generate_random_number()
{
    # check if exactly two arguments have been passed
    test "$#" -eq 2 || print_error_and_exit 5 "generate_random_number(): There have not been passed exactly two arguments!"

    # check if the arguments are both numbers
    is_number "$1" || print_error_and_exit 6 "generate_random_number(): The argument #1 is not a number!"
    is_number "$2" || print_error_and_exit 7 "generate_random_number(): The argument #2 is not a number!"

    # generate one pseudo-random integer within the specified range
    shuf -i "$1-$2" -n 1
}

# ------------------------------------------------------------------------------

activate_window_via_name() {
    # check if exactly one argument has been passed
    test "$#" -eq 1 || print_error_and_exit 8 "activate_window_via_name(): There has not been passed exactly one argument!"

    xdotool search --name "$1" windowactivate --sync
}

# ------------------------------------------------------------------------------

maximize_active_window() {
    # check if no argument has been passed
    test "$#" -eq 0 || print_error_and_exit 9 "maximize_active_window(): There has been passed some argument, none expected!"

    wmctrl -r :ACTIVE: -b add,maximized_vert,maximized_horz
}

# ------------------------------------------------------------------------------

mouse_click() {
    # check if exactly two arguments have been passed
    test "$#" -eq 2 || print_error_and_exit 10 "mouse_click(): There have not been passed exactly two arguments!"

    # check if both of the arguments are numbers
    is_number "$1" || print_error_and_exit 11 "mouse_click(): The argument #1 is not a number!"
    is_number "$2" || print_error_and_exit 12 "mouse_click(): The argument #2 is not a number!"

    # 1. invert the operation_add boolean value,
    #    it seems Bash does not have inbuilt command for that
    # N: operation_add determines whether we will be adding or
    #    subtracting the random number later

    operation_add=$((1 - operation_add))

    # 2. generate pseuso-random integer between 0 and 7, inclusive,
    #    if the generated number is the same as the previous_rand,
    #    generate until it is different
    # N: rand will be later used as pixel offset from the given coordinates

    # we define a constant for randomness

    randomness=7

    rand=$(generate_random_number 0 "$randomness")

    while [ "$rand" -eq "$previous_rand" ]
    do
        rand=$(generate_random_number 0 "$randomness")
    done

    # 3. we don't want to repeat clicks right with the same offset,
    #    so we store information about the previous_rand here

    previous_rand="$rand"

    # 4. depending on the boolean value of operation_add,
    #    we either add the rand, or subtract it to/from the position x/y

    if [ "$operation_add" -eq 1 ]
    then
        pos_x=$(($1 + rand))
        pos_y=$(($2 + rand))
    else
        pos_x=$(($1 - rand))
        pos_y=$(($2 - rand))
    fi

    #  activate Goodgame Empire window and wait for sync,
    #  we need to do this before each click,
    #  because the user may have clicked on some other window
    #  during the 2 second delay
    activate_window_via_name "$window_name_chrome"

    maximize_active_window

    # xdotool can move mouse and simulate button clicks and more
    # ----------------------------------------------------------
        # move the mouse cursor to the given position and wait for sync
        # click the left mouse button
        # restore the original mouse cursor position and wait for sync
        # wait for 2 seconds
    xdotool \
        mousemove --sync "$pos_x" "$pos_y" \
        click 1 \
        mousemove --sync restore \
        sleep 2
}

# ------------------------------------------------------------------------------

mouse_click_coords() {
    while [ "$#" -gt 1 ]
    do
        mouse_click "$1" "$2"

        shift 2
    done

    test "$#" -eq 1 || print_error_and_exit 14 "mouse_click_coords(): Coordinates must be in pairs!"
}

# ------------------------------------------------------------------------------

collect_coins_1920x1080() {
    mouse_click_coords \
        1895 955 \
        1104 691 \
        1131 660 \
        1145 570 \
        1199 381
}


# ------------------------------------------------------------------------------

collect_coins_3840x1080() {
    mouse_click_coords \
        3815 955 \
        3024 691 \
        3051 660 \
        3065 570 \
        3119 381
}

# ------------------------------------------------------------------------------

collect_coins() {
    case "$screen_resolution" in
        1920x1080) collect_coins_1920x1080
        ;;
        3840x1080) collect_coins_3840x1080
        ;;
    esac
}

# ------------------------------------------------------------------------------

if [ "$no_repeat" -eq 0 ]
then
    echo "Repeating coin collecting until CTRL+C is pressed!"

    while true
    do
        collect_coins

        # wait for 10 minutes
        sleep 600
    done
else
    echo "One-time coin collecting!"

    collect_coins
fi

1 个答案:

答案 0 :(得分:2)

我建议将此行重写为if语句

test "$#" -eq 1 || print_error_and_exit 14 "mouse_click_coords(): Coordinates must be in pairs!" }
在我看来,即使$#是neq 1,它仍然会破坏OR的另一半

用伪代码澄清

If parameter count = 1 then
print error
end if