How to deal without goto in Bash?
The typical way to work to use branching in shell scripts would be via functions declared before main block of code. However, I think the underlying issue here is the logical one, and not the goto. Obviously label 1
is repeated, so this can live as function. But also, condition 2 could be turned into a function that also calls label 1
for the sake of readability:
#!/bin/bash
label1(){
echo "label 1 function"
}
check_cond2(){
if ! [ condition2 ]; then
label1 arg1 arg2
fi
}
if [ condition1 ]; then
command
...
command
check_cond2
else
label1
fi
othercommand2
othercommand3
What I've noticed is that in both conditions you have if false exec a block of code
and if false exec a block of code
, so one idea would be to start at checking whether those conditions both false. However, making something like if ! [ cond1 ] || ! [ cond2 ]
would change branching logic. You can still see the pseudocode version of that by seeing this posts edit history.
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.
The below source is slightly modified from the original to make it more robust:
#!/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.
Original source for the code (modified to make it less error prone)
The source for the quote
You should put your block_of_code
into a function and use some if/else:
my_function() {
block of code
...
}
if [[ condition 1 ]] ; then
command
...
command
if [[ ! condition 2 ]] ; then
# label 1
my_function
fi
else
# label 1
my_function
fi
# label 2