Bash - Text stored in variable is not recognized when put it as argument

223 views Asked by At

I am trying to make a script that automates download of SpigotMC BuildTools, detect input version ( sh build.sh <version> ) , and set a variable which is used if the version is greater or equal with 1.14 (since this release, SpigotMC discontinued the automation of auto-compilation of craftbukkit by default. Now it compiles only the spigot jar and I need both of them compiled for my personal purposes.)

Here is what I have tried (I'm a Linux newbie, so this might be messed up):

#!/bin/bash

# Sources:
# Append variables in bash                : https://www.cyberciti.biz/faq/howto-linux-unix-bash-append-textto-variables/
# Check MANIFEST.MF content from jar file : https://www.manongdao.com/q-106728.html
# Check for specified property json file  : https://stackoverflow.com/questions/34543829/jq-cannot-index-array-with-string
#                                           https://www.ultralinux.org/post/json-bash/
# Bash Array                              : https://unix.stackexchange.com/questions/253892/syntax-error-unexpected-when-creating-an-array
# #######################################################################################################################################
# 
# #######################################################################################################################################
# BuildTools Jar Info Variables
# -----------------------------
# BuilsTools working directory
buildtools_root="$(pwd)" # We use $(command) to store "command" output in a variable. We use ${command} if we have to stick other strings near it without whitespace.
# BuildTools jar location
buildtools_jar="$buildtools_root/BuildTools.jar"
# Current BuildTools jar version
buildtools_ver="$(unzip -p "$buildtools_jar" META-INF/MANIFEST.MF | grep 'Implementation-Version:' | cut -d '-' -f 5)"
# Jenkins Api-related variables. 
# A. Retrieve BuildTools lastSuccessfulBuild link
targetJar="$(curl -s 'https://hub.spigotmc.org/jenkins/job/BuildTools/lastSuccessfulBuild/api/json' | jq -r '.artifacts[].relativePath')"
lastSuccessfulBuild="$(curl -s 'https://hub.spigotmc.org/jenkins/job/BuildTools/lastSuccessfulBuild/api/json' | jq -r '.url')"
# B. Make the download link
latestBuildToolsUrl="${lastSuccessfulBuild}artifacts/$targetJar"
# Latest BuildTools Build Version
latestBuildToolsVersion="$(curl -s 'https://hub.spigotmc.org/jenkins/job/BuildTools/lastSuccessfulBuild/api/json' | jq -r '.number')"
displayFullName="$(curl -s 'https://hub.spigotmc.org/jenkins/job/BuildTools/lastSuccessfulBuild/api/json' | jq -r '.fullDisplayName')"
# ---------------------------------------------------------------------------------------------------------------------------------------
# BuildTools Jar Run Variables
# -----------------------------
# 
# #######################################################################################################################################

# This is a function to set java home to current java version in use.
javahome_set () {
    JAVA_HOME=$(dirname "$(dirname "$( readlink -f /etc/alternatives/java )")")

    OIFS=$IFS
    IFS=':';
    for i in $VAR;
    do
            JAVA1=$i/bin/java
            JAVA2=$i/java
            if [ -d "$i" ];
            then
                    if [ ! -L "$JAVA1" ] && [ -x "$JAVA1" ] || [ ! -L "$JAVA2" ] && [ -x "$JAVA2" ]; then
                        echo "dropping path: $i";
                    else
                        NEW=$NEW:$i
                    fi
            fi
    done
    IFS=$OIFS
    JAVA_HOME=$NEW:$JAVA_HOME/bin
    JAVA_HOME=${JAVA_HOME#:*}

}
javahome_set

# This function requires arguments. Checks if $1 >= $2
vercomp () {
    if [[ $1 == $2 ]]
    then
        return 0
    fi
    local IFS=.
    local i ver1=($1) ver2=($2)
    # fill empty fields in ver1 with zeros
    for ((i=${#ver1[@]}; i<${#ver2[@]}; i++))
    do
        ver1[i]=0
    done
    for ((i=0; i<${#ver1[@]}; i++))
    do
        if [[ -z ${ver2[i]} ]]
        then
            # fill empty fields in ver2 with zeros
            ver2[i]=0
        fi
        if ((10#${ver1[i]} > 10#${ver2[i]}))
        then
            return 1
        fi
        if ((10#${ver1[i]} < 10#${ver2[i]}))
        then
            return 2
        fi
    done
    return 0
}

# This is a function to download the latest BuildTools version and check if download is successful.
buildtools_download () {
    curl --silent "$latestBuildToolsUrl" --output BuildTools.jar #Request download to BuildTools.
    if [ "$?" -eq 0 ]; then #Check if file was downloaded. It returns error code non-zero if file was not properly downloaded. (in this  language)
        echo "$Green Successful downloaded BuildTools.$Color_Off"
    else
        echo "$Red Error while downloading BuildTools. $Color_Off"
    fi
}

# This is a function to check for updates for BuildTools jar
buildtools_check () {
    if [ ! -e "$buildtools_jar" ]; then #If BuildTools.jar does NOT exist in "BuildTools" folder
        echo "$Yellow Downloading BuildTools..."
        buildtools_download 
        exit
    elif [ -e "$buildtools_jar" ]; then
        if [ "$buildtools_ver" -lt "$latestBuildToolsVersion" ]; then
            echo "$Blue Updating BuildTools... $Color_Off"
            rm "$buildtools_jar"
            buildtools_download
        fi
    else
        echo "$Cyan BuildTools is up to date. $Color_Off"
    fi
}

info_menu () {
echo "==============================================[Local-Info]=============================================="
echo "BuildTools Root     : $buildtools_root"
echo "Executable Path     : $buildtools_jar"
echo "Installed Version   : $buildtools_ver"
echo "JAVA_HOME Directory : $JAVA_HOME"
echo "=============================================[JsonAPI-Info]============================================="
echo "Latest Download Url: $latestBuildToolsUrl"
echo "========================================================================================================"
echo
if [ "$buildtools_ver" -eq "$latestBuildToolsVersion" ]; then
    echo "$Green You have the latest SpigotMC BuildTools version. $Color_Off"
else
    echo "$Yellow A new build is available : $displayFullName"
fi
echo
}

if [ -z "$1" ]; then
    echo "$BCyan Usage: $0 $BBlue<version> $Color_Off" & exit #By default, $0 is the name of this file
else
    if [ -d "$1" ]; then #If argument is defined
        if [ "$1" = "latest" ]; then
            buildtools_check
        else
            vercomp "$1" "1.14"
            if [ $? -eq 0 -o $? -eq 1 ]; then
                BothJars=(--compile craftbukkit,spigot)  # means $1 >= 1.14 ; sets the $BothJars variable
                buildtools_check
            fi
        if [ "$1" -lt "1.14" ]; then
            echo "$Yellow You want to build an older server version. Good choice btw."
            buildtools_check
        fi
    fi
fi
    rm -rf "$1" && mkdir "$1"
    cd "$1" || exit
    java -jar ./BuildTools.jar --rev "$1" "${BothJars[@]}" --generate-source --generate-docs #../filename is for executing it from one dir far.


I have put comments for you to understand what's going on.

Can someone help me with the problem?

EDIT : If you ever played Minecraft, or if you saw different versions of Minecraft, you can encounter the following version formats:

1.7.10 ; 1.8 ; 1.13.2 ; 1.14 ; 1.15.3 (and no, there is not a '1.8.0' version. Just '1.8')

Here are examples of comparisons between versions which are mathematical false after tr command :

1.8 > 1.7.10 - 18 > 1710
1.14 > 1.13.2 - 114 > 1132

1.15.2 < 1.16 - 1152 < 116

So... There may be problems that could affect the comparison of those numbers, since they are versions, not fractions or integers.

EDIT 2 : I will not make more than 3 edits / post. Thank you Richard K. for helping me with version checking function! I have rewritten my script to make it more complete. I store important parts in functions to save space and to be more visible. Summary : I don't understand what have I done wrong here. U_U

EDIT 3 : As of Rachid K's answer, I got this part to test:

#!/bin/bash

vercomp () {
    if [[ $1 == $2 ]]
    then
        return 0
    fi
    local IFS=.
    local i ver1=($1) ver2=($2)
    # fill empty fields in ver1 with zeros
    for ((i=${#ver1[@]}; i<${#ver2[@]}; i++))
    do
        ver1[i]=0
    done
    for ((i=0; i<${#ver1[@]}; i++))
    do
        if [[ -z ${ver2[i]} ]]
        then
            # fill empty fields in ver2 with zeros
            ver2[i]=0
        fi
        if ((10#${ver1[i]} > 10#${ver2[i]}))
        then
            return 1
        fi
        if ((10#${ver1[i]} < 10#${ver2[i]}))
        then
            return 2
        fi
    done
    return 0
}

if [ -z "$1" ]; then
    echo "$BCyan Usage: $0 $BBlue<version> $Color_Off" & exit #By default, $0 is the name of this file
else
    if [ -d "$1" ]; then #If argument is defined
        if [ "$1" = "latest" ]; then
            echo "Building latest version"
        else
            vercomp "$1" "1.14"
            rc=$?
            case $rc in
            0)
            echo " You want to build version 1.14"
            ;;
            1)
            echo " You want to build version above 1.14"
            ;;
            2)
            echo " You want to build version below 1.14"
            ;;
            latest)
            echo " You want to build latest version."
            ;;
            esac
        fi
    fi
fi

So the vercomp() should see if : $1 is equal with string latest ; $1 is greater or equal with 1.14 ; $1 is lower than 1.14.

The function looks good, but the echo command does not display. I noticed that in some cases the echo command doesn't display due to missing double quotes. So... putting that at it. But it doesn't work. Why?

2

There are 2 answers

9
Rachid K. On BEST ANSWER

Apparently the version you get is either a number like 1.14 or the "latest" string. You need to split you check in two tests. First you check the "latest" value :

if [ "$1" = "latest" ]

and if it is false, check the versions by using the solution proposed in this post

vercomp () {
    if [[ $1 == $2 ]]
    then
        return 0
    fi
    local IFS=.
    local i ver1=($1) ver2=($2)
    # fill empty fields in ver1 with zeros
    for ((i=${#ver1[@]}; i<${#ver2[@]}; i++))
    do
        ver1[i]=0
    done
    for ((i=0; i<${#ver1[@]}; i++))
    do
        if [[ -z ${ver2[i]} ]]
        then
            # fill empty fields in ver2 with zeros
            ver2[i]=0
        fi
        if ((10#${ver1[i]} > 10#${ver2[i]}))
        then
            return 1
        fi
        if ((10#${ver1[i]} < 10#${ver2[i]}))
        then
            return 2
        fi
    done
    return 0
}

So, to compare the version just do:

vercomp "$1" "1.14"
rc=$?
case $rc in
    0) echo '=';;
    1) echo '>';;
    2) echo '<';;
esac
2
welcomeboredom On
  1. I don't see $BCyan and $BMagenta variables defined anywhere so there will just be blank text instead of them.

  2. Problem with condition on line 7 is that you're comparing two string values but you in fact want to compare real numbers (or string "latest"). For real numbers it's best using bc utility. Here's the code equivalent to what you're trying to do (I think):

if [ `echo "$1>=1.14"|bc` -eq 1 ] || [ $1 == "latest" ]; then