callaginn
callaginn

Reputation: 91

How to write a bash function that saves user input to new variable names

Does anyone know how to convert this mac bash statement into a reusable function?
test $var || echo -e "\n$(tput bold)Question for User$(tput sgr0)" && read var

I've got about 30 similar statements in a row and am trying to make it a bit more efficient. I'm thinking this function would be fired with something like this:
userInput "Question for User" var

Upvotes: 0

Views: 628

Answers (3)

callaginn
callaginn

Reputation: 91

I finally managed to piece together this function, which does exactly what I'm trying to do:

userInput () {
    if [[ ${!2} == "" ]]; then
        echo -e "\n$(tput bold)$1$(tput sgr0)" && read newinput
        printf -v $2 "$newinput"
    fi
}

This function tests to see if the variable has a value. If it doesn't, then it captures that information from the user and sets the variable value. Here's a few examples.

If $name isn't set, then this command captures and sets it:

userInput "Enter Your Name" name`

Enter Your Name
John Doe

echo $name
John Doe

If $name is already set, then running this function will do nothing.

name="Frank Smith";
userInput "Your Name" name

// Function does nothing, since $name is set

echo $name
Frank Smith

I've read it depends on some sort of parameter expansion / substitution, but can't really explain what that is or why this works.

Upvotes: 0

Gordon Davisson
Gordon Davisson

Reputation: 125788

If your script runs under bash (not zsh or dash or...), you can do this:

newline=$'\n'
tput_bold=$(tput bold)
tput_sgr0=$(tput sgr0)
userInput() {
    if [[ -z "${!2}" ]]; then
        read -p "${newline}${tput_bold}$1${tput_sgr0}" $2
    fi
}

userInput "Question for User" var

Notes: The critical trick here is to use ${! } to do an indirect variable reference -- the ! makes it essentially dereference twice, so 2 -> var -> the value of $var. Also, echo -e is unreliable; depending on a variety of factors, it might interpret escape characters in the string, or it might print "-e " as part of the output. bash's read -p (prompt) option is much better. Finally, as @l0b0 suggested, I ran the tput command just twice and put the results in variables (along with newline, needed because I'm not using echo -e).

Upvotes: 2

l0b0
l0b0

Reputation: 58788

Some hints:

  • Use More Quotes™. test on its own (which is the same command as test $var if var is empty) is falsy and test some_string in general is truthy (as long as the string doesn't contain special characters used in test expressions).
  • The tput stuff is simply string formatting and has no other side effects, so they can be put into variables to avoid two forks per run.
  • You cannot pass the variable name to a function and have read populate it. You're best off printfing the user response in the function and capturing the string in the caller.
  • Use read's -p option if available.

Upvotes: 1

Related Questions