1

I have a bash script that I want to do something like

read one_thing
read another_thing

And then it runs some code to see if another_thing is available or already taken, and if it is taken, it should warn the user and again run

read another_thing

so we can have a new value, leaving one_thing undisturbed. Since there's no goto in bash, I'm wondering how to do that. My best guess so far is that maybe I should wrap read another_thing inside a function, so that if needed, it will just call itself, but I feel there must be a “cleaner” way to do it. I'm looking for suggestions on efficient ways to do it.

  • 3
    This question would be better suited to stackexchange. Anyway, just enclose your read statement in a while loop, something like while $a==0 and change $a to 1 when another_thing has been read correctly. – terdon Jan 7 '13 at 17:57
  • Provide some real code so we can get a better idea of what you are trying to do. – JamesBarnett Jan 7 '13 at 18:21
  • Scripts and some scripting language questions are ok on SuperUser however most programming issues are better solved using StackOverflow. – James Mertz Jan 7 '13 at 19:13
  • This question may stay here. We've always considered bash scripts on topic, since they're mostly used by power users. – slhck Jan 7 '13 at 19:31
2

You can check for your condition in a loop, and break out of it when it’s met.

#!/bin/bash

read -p 'Input something > ' one_thing

while true; do
  read -p 'Input something else > ' another_thing

  # Write some code to check if the requirements are met
  # Let's say in this case they are when the variable `thing_to_work` equals `done`

  if [[ "${thing_to_work}" == 'abcde' ]]; then
    break # Exit the loop
  else
    echo 'The requirements were not met, so the loop will start again'
  fi
done
2

When I moved from Windows to Linux on my desktop, I had a lot of pre-existing .BAT and .CMD files to convert and I wasn't going to rewrite the logic for them, so I found a way to do a goto in bash that works because the goto function runs sed on itself to strip out any parts of the script that shouldn’t run, and then evals it all:

#!/bin/bash

# BAT / CMD goto function
function goto
{
    label=$1
    cmd=$(sed -n "/^:[[:blank:]][[:blank:]]*${label}/{:a;n;p;ba};" $0 | 
          grep -v ':$')
    eval "$cmd"
    exit
}

apt update

# Just for the heck of it: how to create a variable where to jump to:
start=${1:-"start"}
goto "$start"

: start
goto_msg="Starting..."
echo $goto_msg
# Just jump to the label:
goto "continue"

: skipped
goto_msg="This is skipped!"
echo $goto_msg

: continue
goto_msg="Ended..."
echo "$goto_msg"

# following doesn't jump to apt update whereas original does
goto update

and I do not feel guilty at all as Linus Torvalds famously said:

From: Linus Torvalds
Subject: Re: any chance of 2.6.0-test*?
Date: Sun, 12 Jan 2003 11:38:35 -0800 (PST)

I think goto's are fine, and they are often more readable than large amounts of indentation. That's especially true if the code flow isn't actually naturally indented (in this case it is, so I don't think using goto is in any way clearer than not, but in general goto's can be quite good for readability).

Of course, in stupid languages like Pascal, where labels cannot be descriptive, goto's can be bad. But that's not the fault of the goto, that's the braindamage of the language designer.

Source for code (modified to make it less error prone)
Source for quote

  • 2
    Excellent use case and creative solution! – JakeGould Aug 31 '18 at 1:34
  • @JakeGould Thank you! I knew this was going to attract downvotes for pure philosophical reasons, so your "Thank You" helps me move on as every programmer uses JMP whether want to or not anyway... ;-) – Fabby Aug 31 '18 at 12:03

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.