1

Am having an issue with my Bash script, the script itself works fine however am trying to tidy it up but I cannot find/think of a method as a "goto" command and yes I am very new to Linux Bash.

My code is:

echo "What is the street road?"
read road
echo "What is the address ?"
read address
echo "User is set as: $road"
echo "Address has been set as: $address"


while true; do
    read -p "Is this correct? " yn
    case $yn in
        [Yy]* )  break;;
        [Nn]* )  exit;;
        * ) break;;
    esac
done

When the user inputs "n" the script will just exit itself, but am trying to tidy it up so it will just re-loop itself here. So if the user inputs "n" it will just re-ask them again for the road and address.

I know in .bat you can do :A goto :A (Or something like that!) But in Bash am not sure how to do this?

Thanks everyone!

Cyrus
  • 84,225
  • 14
  • 89
  • 153
Bac0n
  • 29
  • 2
  • 7

4 Answers4

3

I suggest you use this with GNU bash:

#!/bin/bash

until [[ $yn =~ ^[Yy]$ ]]; do
   read -p "What is the street road? " road
   read -p "What is the address ? " address

   echo "User is set as: $road"
   echo "Address has been set as: $address"

   read -p "Is this correct? " yn
done

# continue with your code here
mklement0
  • 382,024
  • 64
  • 607
  • 775
Cyrus
  • 84,225
  • 14
  • 89
  • 153
  • Nice use of the regex comparison. You should also handle the case where `$yn` is negatory (which, in the OP, leads to exiting the script altogether). – Sebastian Lenartowicz Aug 17 '16 at 04:44
  • ++, but please note that the term "GNU bash" is redundant and confusing, because GNU Bash is the only Bash there is, which is why it needs no qualification (especially given that the question is tagged `bash`). – mklement0 Aug 17 '16 at 04:47
  • @mklement0: Thank you. I use the "GNU bash" deliberately. Busybox' bash implementation differs from GNU bash's implementation. An example of this: Busybox' bash was not vulnerable to the Bash bug [ShellShock](https://en.wikipedia.org/wiki/Shellshock_%28software_bug%29). – Cyrus Aug 17 '16 at 05:04
  • 1
    @Cyrus: I've never used BusyBox, but Wikipedia tells me that it doesn't use Bash at all: ["BusyBox uses the Almquist shell, also known as A Shell, ash and sh."](https://en.wikipedia.org/wiki/BusyBox#Features). – mklement0 Aug 17 '16 at 05:21
  • @mklement0: Good catch! There are more implementations of bash, e.g. cygwin bash and win-bash. – Cyrus Aug 17 '16 at 05:31
  • 1
    From what I understand, _Cygwin Bash_ is _regular_ Bash source code, compiled for the [Cygwin library on Windows](https://cygwin.com/faq.html#faq.about). By contrast, _win-bash_ is a _fringe project_ forked from an _ancient_ version of Bash: ["First of all, you should keep in mind that win-bash is based on a old version of bash (1.14.2) while cygwin -bash is more or less up to date."](http://win-bash.sourceforge.net/). Thus, I suggest sticking with just "Bash" to refer to the official GNU Bash, and calling out fringe projects such as win-bash only when actually needed, to avoid confusion. – mklement0 Aug 17 '16 at 05:49
0

I'd rewrite your script like this:

ask () {
    echo "$1"
    read answer

    while true; do
        read -p "Is this correct? " yn
        case $yn in
            [Yy]* )  break;;
            [Nn]* )  exit;;
            * ) break;;
        esac
    done

    eval "$2='$answer'"
}

ask "What is your street?" street
ask "What is the address?" address
echo "Your address has been set to $address $street"

Like I mentioned in my comment on your question, using goto, in any language, is generally considered bad form (because it leads to hard-to-debug code, except in very specific circumstances), and bash does not have a goto like you find in other languages in any event. If you find yourself writing code that you think requires a goto, please take a moment, lean back from the keyboard, and re-evaluate your premise a little. 99.999% of the time, you'll find you don't actually need it, and there's a structured-programming approach that'll accomplish the same thing much more neatly.

Community
  • 1
  • 1
Sebastian Lenartowicz
  • 4,695
  • 4
  • 28
  • 39
0

You could go radical:

ok=no
while   read -p "What is the street road? " road &&
        read -p "What is the address? " address &&
        echo "Road is set to: $road" &&
        echo "Address has been set as: $address" &&
        read -p "Is this correct? " yn
do
    case $yn in
    ([Yy]*) echo "Great!"; ok=yes; break;;
    ([Nn]*) echo "OK - then try again";;
    (*)     echo "Didn't understand that - it did not look like Y or N";;
    esac
done

if [ "$ok" = "yes" ]
then : OK to use answers
else : Do not use answers
fi

This exploits the fact that you can have an arbitrary list of commands as the 'condition' in a while loop. I've chained the commands together with && so they all have to succeed, but you could have independent commands, in which case the last one is the one that counts. I also exploited the read -p 'prompt' var notation for the initial values as well as the 'Is this correct' one.

Sample dialogue:

$ bash prompt.sh
What is the street road? California
What is the address? 1189
Road is set to: California
Address has been set as: 1189
Is this correct? n
OK - then try again
What is the street road? California Ave
What is the address? 2291
Road is set to: California Ave
Address has been set as: 2291
Is this correct? y
Great!
$
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
0

A bit atypical, but you could do:

#!/bin/sh
while
    read -p 'What is the street road? ' road
    read -p 'What is the address ? ' address
    echo "User is set as: $road"
    echo "Address has been set as: $address"
    read -p "Is this correct? " yn
    case $yn in
        [Yy]* )  false;;
        * )  true;;
    esac
do
    :
done
echo "User is set as: $road"
echo "Address has been set as: $address"
William Pursell
  • 204,365
  • 48
  • 270
  • 300