5

In a set of if/elif/else/fi statements, I have made 'else' present the user with an error message, but I also want it to take the user back to the question which was asked before the if/else statements so that they can try to answer it again.

How do I take the user back to a previous line of code? Or, if this is not possible, is there another way to do this?

0

2 Answers 2

8

I think the easiest way would be to wrap the prompting code into a function, and then drop it into an until loop.

Since all you need really is to call the function until it succeeds, you can put the noop command ":" in the until loop.

Something like this:

#!/bin/bash

getgender() {
  read -p "What is the gender of the user? (male/female): " gender
  case "$gender" in
    m|M)
      grouptoaddto="boys"
      return 0
      ;;
    f|F)
      grouptoaddto="girls"
      return 0
      ;;
    *)
      printf %s\\n "Please enter 'M' or 'F'"
      return 1
      ;;
  esac
}

until getgender; do : ; done
sudo usermod -a -G "$grouptoaddto" "$username"

The point here is the function called with until, so it is repeatedly called until it succeeds. The case switch within the function is just an example.


Simpler example, without using a function:

while [ -z "$groupname" ]; do
  read -p "What gender is the user?" answer
  case "$answer" in
    [MmBb]|[Mm]ale|[Bb]oy) groupname="boys" ;;
    [FfGg]|[Ff]emale|[Gg]irl) groupname="girls" ;;
    *) echo "Please choose male/female (or boy/girl)" ;;
  esac
done
sudo usermod -a -G "$groupname" "$username"

In this last example, I'm using the -z switch to the [ (test) command, to continue the loop as long as the "groupname" variable has zero length.

The keynote is the use of while or until.

To translate this last example into human readable pseudocode:

While groupname is empty,

  ask user for gender.

  If he answers with one letter "m" or "B",
    or the word "Male" or "boy",
    set the groupname as "boys".

  If she answers with one letter "F" or "g",
    or the word "female" or "Girl",
    set the groupname as "girls".

  If he/she answers anything else, complain.

(And then repeat, since groupname is still empty.)

Once you have groupname populated,
  add the user to that group.

Yet another example, without the groupname variable:

while true; do
  read -p "What gender is the user?" answer
  case "$answer" in
    [MmBb]|[Mm]ale|[Bb]oy)
      sudo usermod -a -G boys "$username"
      break
      ;;
    [FfGg]|[Ff]emale|[Gg]irl)
      sudo usermod -a -G girls "$username"
      break
      ;;
    *) echo "Please choose male/female (or boy/girl)" ;;
  esac
done
8
  • Thanks, but is this something completely different from a if/else statement? It looks complicated. Commented Mar 9, 2016 at 22:13
  • @Kaiylar, not too complicated. It's a case switch which is often clearer than if/elif/elif/elif/else, especially for pattern matching. I'll update with a simpler example. Commented Mar 9, 2016 at 22:15
  • Thanks, I've read it. I somewhat understand, but I'm not sure what to do in my situation. I am making a user creation program, and after the user is created, the user is asked whether they are a boy or a girl, for example, and depending on their answer, the new user is placed into the corresponding group using the command 'sudo usermod -a -G <boys/girls> $username'. If they don't answer with either 'B' or 'b' or 'G' or 'g', they'll be presented with an error and taken back to the question. So, which of these methods should I use in this situation? Commented Mar 9, 2016 at 22:41
  • 1
    You could put the sudo command in right away, but I don't know what you would use for the while loop test in that case. The way I have it written, it runs until the $groupname variable is populated, which is an easy test. I see no particular advantage to putting the sudo command in earlier. Commented Mar 13, 2016 at 20:12
  • 1
    [MmBb] etc. are using standard shell globs; the square brackets are for "any one of the enclosed characters." You might want to read some more examples of globs. Commented Mar 13, 2016 at 20:12
2
flag=1
while [ ${flag} -eq 1 ]
do
  read -p "Please answer B or G " bg
  if [ "${bg}" = B ] || [ "${bg}" = b ] 
  then
    flag=0
    groupname=boys
  else 
    if [ "${bg}" = G ] || [ "${bg}" = g ]
    then
      flag=0
      groupname=girls
    fi
  fi
done
sudo usermod -a -G ${groupname} $username

this is the simplest way I can think of, while clearly showing what it happening.

8
  • Thanks for the answer. I was thinking of something like that where you define a variable and change it depending on which statement is true. I'll try this too. Commented Mar 9, 2016 at 22:51
  • You could simplify this with elif. Or just use a case switch; that's what they're for as the code gets awfully redundant without them. And you should quote your variables in the last line. Commented Mar 9, 2016 at 23:58
  • Yes I totally agree with you but looking at the comments user provided to the previous answer, I tried to make it as simple and as clear as possible. Hence the very, very basic commands Commented Mar 10, 2016 at 0:24
  • 2
    Granted for simplicity, but quoting variables isn't more complicated, and it's arguably even more important to quote them for beginners, who may be utterly mystified by the errors they will get otherwise. Commented Mar 10, 2016 at 1:12
  • 1
    it is not merely opinion that failing to quote variables is bad practice, it is fact. You can have your own opinions, but not your own facts. As for Kaiylar's question "which to use?", IMO @Wildcard's examples (both of them) are better and simpler, and easier to understand and to modify in future. Commented Mar 11, 2016 at 2:01

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.