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

Why does my POSIX shell script exit?

我不是 shell 脚本方面的专家,但是如果我的下面的脚本以 -1 选项启动或不使用它,我会尽量避免 exit

./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 "" -eq "" 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 "" || 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 Exit code = .$nocolor" >&2
    exit ""
}

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

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 "" > /dev/null 2>&1 || print_error_and_exit 127 "check_for_prerequisite(): I require  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 "" || print_error_and_exit 16 "print_usage_and_exit(): The argument is not a number! Exit code expected."

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

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

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 }')

# 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 "" || print_error_and_exit 6 "generate_random_number(): The argument #1 is not a number!"
    is_number "" || 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 "-" -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 "" 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 "" || print_error_and_exit 11 "mouse_click(): The argument #1 is not a number!"
    is_number "" || 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=$(( + rand))
        pos_y=$(( + rand))
    else
        pos_x=$(( - rand))
        pos_y=$(( - 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 "" ""

        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

我建议将这一行重写为 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