1

I am trying to write a generic "confirm" function for bash that asks for input, and based on a default value of [Yy] or [Nn] returns a 0 or 1 to the calling function.

It works, but:

  • I find the code to be a little hard to follow if I read it later (the must_match handling logic, specifically)
  • I'm not sure if I am using any feature of return values of functions that is not portable (there are many threads on SO about handling return values using local variables, evals, and other mechanisms. As another example, I found out ${VAR,,} to convert strings to lowercase is not supported in OSX bash even today - Feb 2019)

Can you suggest if this is a good way and/or how I can improve it:

My function:

confirm() {
    display_str=$1
    default_ans=$2
    if [[ $default_ans == 'y/N' ]]
    then
        must_match='yY'
    else
       must_match='nN'
    fi
    read -p "${display_str} [${default_ans}]:" ans
    if [[ $ans == [$must_match] ]]
    then
        [[ $must_match == 'yY' ]] && return 0 || return 1
    else
        [[ $must_match == 'yY' ]] && return 1 || return 0
    fi

}

How I use it:

confirm 'Install Server' 'y/N'  && install_es  || echo 'Skipping server install'
confirm 'Install hooks' 'Y/n'  && install_hooks  || echo 'Skipping machine learning hooks install'

Portability: Using the term informally, should work on popular Linux distros, say, over the last 5 years. Put another way, as portable as you can make it for linux systems.

(I am aware of other threads about confirm functions, but they seem to only handle Y/n)

3
  • You have to define what you mean by "portable". Usually, it means that it conforms to the POSIX standard. You seem to mean it should work in bash 3.2 or later.
    – chepner
    Commented Feb 16, 2019 at 13:58
  • @chepner thank you - added clarification Commented Feb 16, 2019 at 14:04
  • 1
    Note that almost any reasonably up-to-date Linux distribution will ship with bash 4 or later, and thus support ${var,,} (not that you need it here). macOS, for licensing reasons, does not and is never likely to ship a version later than 3.2. (You are free to install a newer version if you like, if the machines you are targeting are under your control.)
    – chepner
    Commented Feb 16, 2019 at 14:14

1 Answer 1

1

The exit status of confirm is just the exit status of the last command executed. That means all you need to do is end with [[ $ans == [$must_match] ]]; regardless of what must_match is, if $ans matches it this returns 0, and if it doesn't it returns 1.

On a style note, I would set must_match to the pattern itself, rather than the characters that will appear in the pattern.

confirm() {
    display_str=$1
    default_ans=$2
    if [[ $default_ans == 'y/N' ]]
    then
       must_match='[yY]'
    else
       must_match='[nN]'
    fi
    read -p "${display_str} [${default_ans}]:" ans
    [[ $ans == $must_match ]]
}
0

Not the answer you're looking for? Browse other questions tagged or ask your own question.