In a bash script, how would you script the following ?

USER_INPUT="1 2 3 4 5"
echo "Please select one of the following values: $USER_INPUT"
Prompt the user to choose a value in $USER_INPUT.
echo "command <user input> <iterate through remaining numbers not selected from $USER_INPUT>

For example, if the user selects "2", the following commands are run.

command 2 1
command 2 3
command 2 4
command 2 5

3 Answers 3


values=( "Why is" "a raven" "like a" "writing desk?" )

select word in "${values[@]}"; do
    if [[ -z "$word" ]]; then
        printf '"%s" is not a valid choice\n' "$REPLY" >&2
        user_in="$(( REPLY - 1 ))"

for (( i = 0; i < ${#values[@]}; ++i )); do
    if (( i != user_in )); then
        printf 'You did not pick "%s"\n' "${values[$i]}"

The select command will present the user with a menu of choices. Upon picking a menu item, $REPLY will be the number that the user entered, and $word will be the value in the menu corresponding to that number. If an invalid choice is made, $word will be empty.

The second part iterates over our array (which corresponds to your $USER_INPUT string) using the C-like for loop in bash. If we come upon the index that the corresponds to the chosen value, we skip it. We print out all other values from our array.

You may obviously execute commands in the loop to:

for (( i = 0; i < ${#values[@]}; ++i )); do
    if (( i != user_in )); then
        printf 'command %s %s\n' "$user_in" "${values[$i]}"

or even

for (( i = 0; i < ${#values[@]}; ++i )); do
    if (( i != user_in )); then
        command "${values[$user_in]}" "${values[$i]}"

which will try to run the actual things in $values as a command.

Testing it (with the first version of the loop):

$ bash script.sh
1) Why is
2) a raven
3) like a
4) writing desk?
#? B
"B" is not a valid choice
#? 0
"0" is not a valid choice
#? 3
You did not pick "Why is"
You did not pick "a raven"
You did not pick "writing desk?"

If you can afford to modify $values, and just want to output the things that the user didn't pick, then the second part of the script (the loop) may be replaced with

unset values[$user_in]
printf 'You did not pick "%s"\n' "${values[@]}"
PROMPT=(1 2 3 4 5)
for i in ${PROMPT[*]}
    printf " %d\n" $i
echo "Choose an option: "

read var

unset PROMPT[$var-1]

for n in ${PROMPT_new[*]}
    echo `command $var $n`
  • 2
    Had to add "}" to $PROMPT_new.
    – uihdff
    Aug 30, 2017 at 7:01
  • 2
    Yes. Sorry for the typo. I am correcting it. Thanks @uihdff
    – Bussller
    Aug 30, 2017 at 7:24

Accept your input on the command line, not interactively. (Please!)

This is simple enough I would just use a shell function.

iter_the_command() {
  [ "$#" -eq 1 ] && [ "$1" -ge 1 ] && [ "$1" -le "$max" ] ||
    { printf 'Error: please pass a number from 1 to %d\n' "$max" >&2;
      return 1;}
  for i in $(seq "$max"); do
    [ "$i" -eq "$1" ] && continue
    somecommand "$1" "$i"

However, I have a strong suspicion this is an XY question and what you're really trying to do would be more easily accomplished directly. (In other words, I find it hard to imagine a scenario where the above code would actually be useful and perform a needed function not better done otherwise.)


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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