Search code examples
bashfunctionvariablesconfirmindirection

how to write a Bash function that confirms the value of an existing variable with a user


I have a large number of configuration variables for which I want users to issue confirmation of the values. So, there could be some variable specifying a run number in existence and I want the script to ask the user if the current value of the variable is ok. If the user responds that the value is not ok, the script requests a new value and assigns it to the variable.

I have made an initial attempt at a function for doing this, but there is some difficulty with its running; it stalls. I would value some assistance in solving the problem and also any criticisms of the approach I'm using. The code is as follows:

confirmVariableValue(){
    variableName="${1}"
    variableValue="${!variableName}"
    while [[ "${userInput}" != "n" && "${userInput}" != "y" ]]; do
        echo "variable "${variableName}" value: "${variableValue}""
        echo "Is this correct? (y: continue / n: change it / other: exit)"
        read userInput
        # Make the user input lowercase.
        userInput="$(echo "${userInput}" | sed 's/\(.*\)/\L\1/')"
        # If the user input is "n", request a new value for the variable. If the
        # user input is anything other than "y" or "n", exit. If the user input
        # is "y", then the user confirmation loop ends.
        if [[ "${userInput}" == "n" ]]; then
            echo "enter variable "${variableName}" value:"
            read variableValue
        elif [[ "${userInput}" != "y" && "${userInput}" != "n" ]]; then
            echo "terminating"
            exit 0
        fi
    done
    echo "${variableValue}"
}

myVariable="run_2014-09-23T1909"
echo "--------------------------------------------------------------------------------"
echo "initial variable value: "${myVariable}""
myVariable="$(confirmVariableValue "myVariable")"
echo "final variable value: "${myVariable}""
echo "--------------------------------------------------------------------------------"

Solution

  • The problem is here:

    myVariable="$(confirmVariableValue "myVariable")"
    

    your questions, like

        echo "Is this correct? (y: continue / n: change it / other: exit)"
    

    are going into the myVariable and not to the screen.

    Try print questions to STDERR, or any other file-descriptor but STDOUT.

    Opinion based comment: I would be unhappy with such config-script. It is way too chatty. For me is better:

    • print out the description and the default value
    • and ask Press Enter for confirm or enter a new value or <something> for exit>

    You can also, use the following technique:

    • use the bash readline library for the read command with -e
    • use the -i value for set the default value for the editing
    • use the printf -v variable to print into variable, so you don't need to use var=$(...) nor any (potentially) dangerous eval...

    example:

    err() { echo "$@" >&2; return 1; }
    
    getval() {
        while :
        do
            read -e -i "${!1}" -p "$1>" inp
            case "$inp" in
                Q|q) err "Quitting...." || return 1 ;;
                "") err "Must enter some value" ;;
                *)
                    #validate the input here
    
                    #and print the new value into the variable
                    printf -v "$1" "%s" "$inp"
                    return 0
                    ;;
            esac
        done
    }
    
    somevariable=val1
    anotherone=val2
    x=val3
    
    for var in somevariable anotherone x
    do
        getval "$var" || exit 
        echo "new value for $var is: =${!var}="
    done