1

I have a shell script script.sh like this:

names=( jack john jerry)

And I want the user to type any of these three names as its first parameter, just like:

./script.sh jack

If the user typed a wrong one, for example

./script.sh kate

It will trigger a exit and ask the user to only type one from those 3.

What should I do?

4
names=(jack john jerry); 
if [[ " "${names[@]}" " == *" "$1" "* ]] ;then 
    echo "$1: ok"
else 
    echo "$1: not recognized. Valid names are:"
    echo "${names[@]/%/,}"
    exit 1
fi

The above code works for names which do not contain whitespace.
The modified version, below, can handle whitespace in names.

names=("flash jack" john jerry); 
d=$'\1'   # validation delimiter - value is \x01
valid="${names[@]/%/$d}"
valid="$d${valid//$d /$d}"
if [[ $valid == *$d$1$d* ]] ;then 
    echo "$1: ok"
else 
    echo "$1: not recognized. Valid names are:"
    echo "${names[@]/%/,}"
    exit 1
fi

Output for whitespace aware version:

flash jack: ok

or

kate: not recognized. Valid names are:
flash jack, john, jerry,
  • Note: this can result in false positives if your input or list of names contains spaces – Chris Down Sep 4 '15 at 14:39
  • That's true Chris... but I intentionally answered as per the input data provided... Have now added whitespace capable version. – Peter.O Sep 4 '15 at 15:25
0

That's precisely what case statements are for:

#! /bin/bash

case $1 in
    [Jj]ack)
        echo "You chose Jack!"
    ;;
    [Jj]ohn)
        echo "You chose John!"
    ;;
    [Jj]erry)
        echo "You chose Jerry!"
    ;;
    ## For all other cases
    *)
        echo 'Please choose one of "John", "Jack" or "Jerry"' >&2
    exit 1
esac

The case statement will be run on the value of $1, the first parameter you pass to your script. If it is either jackor Jack, the first choice will be run, if it's John or john the second etc. If anything else is entered, the last statement will be run.

-1

Firstly, I need to mention that shell scripts substantial enough to use the horrid array implementation are probably going to be regarded as the spawn of the devil. Also, you didn't indicate what shell, but I am assuming bash.

There are many ways to do this, all ugly.

1) Iterate over the array. It's readable and relatively clean, but inefficient.

for i in 0 1 2 3 4
do
echo compare ${ARRAY[$i]} perhaps using test or whatever you like
done

2) Use expr to do it all at once. This is fragile and will break if one name is a substring of another. That can be fixed, but I would recommend using a better tool if it comes to that

$ ARRAY=(jack john jerry )
$ expr "${ARRAY[*]}" : '.*jack.*'
15  # it's found
$ expr "${ARRAY[*]}" : '.*sue.*'
0   # not found

Where jack or sue are replaced by $1 or whatever arg you want to check.

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.