GOTO in BASH

For discussions about programming and projects not necessarily associated with Porteus.
Bogomips
Full of knowledge
Full of knowledge
Posts: 2564
Joined: 25 Jun 2014, 15:21
Distribution: 3.2.2 Cinnamon & KDE5
Location: London

GOTO in BASH

Post#1 by Bogomips » 27 Aug 2015, 14:37

Searching for something else, came across this little gem: goto in bash
goto in bash
October 26, 2012hackingbash, basic-hate

If you are as old and nerdy as I, you may have spent your grade school days hacking in the BASIC computer language. One of the (mostly hated) features of the (mostly hated) language was that any statement required a line number; this provided both the ability to edit individual lines of the program without a screen editor, as well as de facto labels for the (mostly hated) GOTO and GOSUB commands. But you could also use line numbers to run your program starting from any random point: “RUN 250″ might start in the middle of a program, typically after line 250 exited with some syntax error and was subsequently fixed.

Today, in bash, we have no such facility. Why on earth would anyone want it, with the presence of actual flow control constructs? Who knows, but asking Google about “bash goto” shows that I am not the first.

For my part, at $work, I have a particular script which takes several days to run, each part of which may take many hours, and, due to moon phases, may fail haphazardly. If a command fails, the state up to that point is preserved, so I just need to continue where that left off. Each major part of the job is already factored into individual scripts, so I could cut-and-paste commands from the failure point onward, but I’m lazy.

Thus, I present bash goto. It runs sed on itself to strip out any parts of the script that shouldn’t run, and then evals it all. Prepare to cringe.

    Code: Select all

    #!/bin/bash
    # include this boilerplate
    function jumpto
    {
        label=$1
        cmd=$(sed -n "/$label:/{:a;n;p;ba};" $0 | grep -v ':$')
        eval "$cmd"
        exit
    }
    
    start=${1:-"start"}
    
    jumpto $start
    
    start:
    # your script goes here...
    x=100
    jumpto foo
    
    mid:
    x=101
    echo "This is not printed!"
    
    foo:
    x=${x:-10}
    echo x is $x
    results in:

    Code: Select all

    $ ./test.sh
    x is 100
    $ ./test.sh foo
    x is 10
    $ ./test.sh mid
    This is not printed!
    x is 101
    
      My quest to make bash look like assembly language draws ever nearer to completion.
      @Rava
      Can you explain what's going on here in words of one syllable?
      Linux porteus 4.4.0-porteus #3 SMP PREEMPT Sat Jan 23 07:01:55 UTC 2016 i686 AMD Sempron(tm) 140 Processor AuthenticAMD GNU/Linux
      NVIDIA Corporation C61 [GeForce 6150SE nForce 430] (rev a2) MemTotal: 901760 kB MemFree: 66752 kB

      User avatar
      Ed_P
      Contributor
      Contributor
      Posts: 8315
      Joined: 06 Feb 2013, 22:12
      Distribution: Cinnamon 5.01 ISO
      Location: Western NY, USA

      Re: GOTO in BASH

      Post#2 by Ed_P » 27 Aug 2015, 15:03

      Bogomips wrote:@Rava
      Can you explain what's going on here in words of one syllable?
      :D Yes please. :)

      But it seems to be more of a PERFORM or CALL of a subroutine rather than a GOTO. But still useful. :good:
      Ed

      port
      Samurai
      Samurai
      Posts: 137
      Joined: 18 Feb 2016, 09:25
      Distribution: Linux porteus 3.2.2 KDE
      Location: Spain

      Re: GOTO in BASH

      Post#3 by port » 23 Feb 2016, 19:15

      it is a jump in the same way as it is in DOS .bat files.

      Code: Select all

      echo "done!"
      goto next
      echo "not done"
      :next
      echo "also done!"
      
      but this is a backward step to spaghetti code, why to go backwards when we have structured programing in bash? ;-)

      User avatar
      Ed_P
      Contributor
      Contributor
      Posts: 8315
      Joined: 06 Feb 2013, 22:12
      Distribution: Cinnamon 5.01 ISO
      Location: Western NY, USA

      Re: GOTO in BASH

      Post#4 by Ed_P » 23 Feb 2016, 21:53

      Trust me, crappy code can be written using structured programming just like efficient well written code could be written using gotos. The language isn't what makes a program sloppy or inefficient, the programmer is.

      This example seems pretty clear and clean to me.

      Code: Select all

      @echo off
      if exist c:\*.tmp goto :tmps
      if exist c:\*.log goto :logs
      goto :end
      
      :tmps
      echo c:\*.tmp files
      dir c:\*.tmp
      goto :end
      
      :logs
      echo c:\*.log files
      dir c:\*.log
      goto :end
      
      :end
      echo Finished
      Ed

      port
      Samurai
      Samurai
      Posts: 137
      Joined: 18 Feb 2016, 09:25
      Distribution: Linux porteus 3.2.2 KDE
      Location: Spain

      Re: GOTO in BASH

      Post#5 by port » 06 Mar 2016, 19:07

      Yes, I know programming style is a matter of BCAK and thus you can produce spaghetti code with structured programing as well as using goto's and in fact pretty old assembly code could be a great example of efficient well written code... but there's a key difference, pretty old assembler has RET statement while DOS scripting (aka BAT files) does not and that's the key point about language contrbuting to crappy code, let's see in in you own example

      It's seems pretty clear and clean at first sight but what if you need to call a subroutine inside your rutine? crappiness appeared!

      Code: Select all

      @echo off
      if exist c:\*.tmp goto :tmps
      if exist c:\*.log goto :logs
      goto :end
      
      :tmps
      echo c:\*.tmp files
      dir c:\*.tmp
      goto stats
      :statsret
      echo c:\ dirs
      tree
      goto :end
      
      :logs
      echo c:\*.log files
      dir c:\*.log
      goto :end
      
      :stats
      dir c:\*.tmp | find /v /c "%@$fake&*" | more
      goto statsret
      
      :end
      echo Finished
      
      DOS batch scripting ins inherently crappy and I think is better not to emulate it from more powerfull bash scripting ;-)

      User avatar
      Ed_P
      Contributor
      Contributor
      Posts: 8315
      Joined: 06 Feb 2013, 22:12
      Distribution: Cinnamon 5.01 ISO
      Location: Western NY, USA

      Re: GOTO in BASH

      Post#6 by Ed_P » 06 Mar 2016, 20:24

      Or

      Code: Select all

      @echo off
      if exist c:\*.tmp goto :tmps
      if exist c:\*.log goto :logs
      goto :end
      
      :tmps
      echo c:\*.tmp files
      dir c:\*.tmp
      call  :stats
      :statsret
      echo c:\ dirs
      tree
      goto :end
      
      :logs
      echo c:\*.log files
      dir c:\*.log
      goto :end
      
      :stats
      dir c:\*.tmp | find /v /c "%@$fake&*" | more
      goto :eof
      
      :end
      echo Finished
      
      :good:
      Ed

      port
      Samurai
      Samurai
      Posts: 137
      Joined: 18 Feb 2016, 09:25
      Distribution: Linux porteus 3.2.2 KDE
      Location: Spain

      Re: GOTO in BASH

      Post#7 by port » 06 Mar 2016, 21:27

      This is a bit tricky because call command only allows calling to a label in windows batch scripting, in pure prior msdos you only can call another batch file as far as I know

      Anyway I suppose you agree msdos batch scripting is tricky and head you to crappy code style. Windows has improved things even to a great level when considering powershell

      User avatar
      Ed_P
      Contributor
      Contributor
      Posts: 8315
      Joined: 06 Feb 2013, 22:12
      Distribution: Cinnamon 5.01 ISO
      Location: Western NY, USA

      Re: GOTO in BASH

      Post#8 by Ed_P » 06 Mar 2016, 23:28

      port wrote:prior msdos you only can call another batch file as far as I know
      You have a good memory. I believe that was indeed the case.
      Anyway I suppose you agree msdos batch scripting is tricky and head you to crappy code style.
      I'm pretty sure any programming style can lead to crappy code. It depends on the size of the code, the programmer(s) involved, and when the program has to be implemented.
      Ed

      Dave99
      Black ninja
      Black ninja
      Posts: 54
      Joined: 19 Apr 2014, 20:15
      Distribution: Porteus
      Location: R.S.A.

      Re: GOTO in BASH

      Post#9 by Dave99 » 15 Apr 2016, 00:08

      @Bogomips

      Rather like your goto in Bash, reminds me of the old Basic days.
      Actually your post got me thinking, how much could one replicate the Basic language in Bash.

      Bash has no means of creating macros like in MASM or NASM but it does have the "source" command and when used with functions, we could replicate some of the Basic language commands.

      So one could first create a file and call it say basic.inc which could amongst other things contain:

      Code: Select all

      #!/usr/bin/env bash
      
      print()
      {
      echo $1
      }
      
      rem()
      {
        :
      }
      
      cls()
      {
      clear
      }
      
      # and so on.....
      
      Then include the basic.inc file in a Bash script like so:

      Code: Select all

      #!/usr/bin/env bash
      
      source /path/to/basic.inc
      
      # The two lines above now the only non-Basic lines.
      
      print "hello just testing the new print command"
      rem this is just a comment, does nothing
      sleep 2    # same as in Basic
      cls
      
      Obviously not too useful but fun. :D

      Dave

      User avatar
      Rava
      Contributor
      Contributor
      Posts: 5401
      Joined: 11 Jan 2011, 02:46
      Distribution: XFCE 5.01 x86_64 + 4.0 i586
      Location: Forests of Germany

      Re: GOTO in BASH

      Post#10 by Rava » 16 Apr 2016, 07:02

      I had no idea ":" is also a comment in bash, I always use "#"

      What is the difference to "#"?

      Seems there are too many instances of ":" to be found in man bash to get what I ask it for. :)
      Cheers!
      Yours Rava

      Dave99
      Black ninja
      Black ninja
      Posts: 54
      Joined: 19 Apr 2014, 20:15
      Distribution: Porteus
      Location: R.S.A.

      Re: GOTO in BASH

      Post#11 by Dave99 » 16 Apr 2016, 07:30

      Hi Rava

      Interesting point about : and #

      Have a look here:

      http://stackoverflow.com/questions/1240 ... op-in-bash

      User avatar
      Rava
      Contributor
      Contributor
      Posts: 5401
      Joined: 11 Jan 2011, 02:46
      Distribution: XFCE 5.01 x86_64 + 4.0 i586
      Location: Forests of Germany

      Re: GOTO in BASH

      Post#12 by Rava » 16 Apr 2016, 07:57

      Me thinks this answer nails it quite good:
      It's there more for historical reasons. The colon builtin : is exactly equivalent to true. It's traditional to use true when the return value is important, for example in an infinite loop:

      while true; do
      echo 'Going on forever'
      done

      It's traditional to use : when the shell syntax requires a command but you have nothing to do.

      while keep_waiting; do
      : # busy-wait
      done
      with what someone added:

      Because : is a command, the shell still has to process its arguments before it can discover that : ignores them. Mostly, you are just making the shell do extra work in expanding * to a list of files in the current directory; it won't actually affect how the script works. – chepner Nov 5 '14 at 14:48


      I suppose it might make your script fail if you happen to run in in a directory with a lot of files, making the glob expansion go over the command length limit? Maybe only if you have set -e on. Anyway, hopefully we can all just agree to use # :) – Jack O'Connor Nov 7 '15 at 22:14
      :D


      So, in short, nope, ":" is not a comment!
      It is a "program" that ignores all parameters, but like the comments above, using "* * *" could make a script crash. xD

      But.... using "#" instead of ":" would not work, cause for bash "#" is like ""
      Cheers!
      Yours Rava

      Dave99
      Black ninja
      Black ninja
      Posts: 54
      Joined: 19 Apr 2014, 20:15
      Distribution: Porteus
      Location: R.S.A.

      Re: GOTO in BASH

      Post#13 by Dave99 » 16 Apr 2016, 09:23

      @Rava
      So, in short, nope, ":" is not a comment!
      Correct and the easy way to test it as follows:

      This works as there is a command in the function even though it does nothing:

      Code: Select all

      DoNothing()
      {
        :
      }
      
      While this will not work as there is only a comment:

      Code: Select all

      DoNothing()
      {
        # let's do nothing
      }
      

      Bogomips
      Full of knowledge
      Full of knowledge
      Posts: 2564
      Joined: 25 Jun 2014, 15:21
      Distribution: 3.2.2 Cinnamon & KDE5
      Location: London

      Re: GOTO in BASH

      Post#14 by Bogomips » 16 Apr 2016, 18:12

      Found a use for the ':" :Yahoo!: This is in tab expansion. So far been having to use ls for a non-executable, but now:

      Code: Select all

      guest@porteus:~$ p10/tmp/iso/       # And no further!
      # but here:
      guest@porteus:~$ :p10/tmp/iso/Porteus-XFCE-x86_64.iso
      
      Also just written something v. long to mount, and forgotten to mkdir mountpoint, so stuck : in front of it all.

      Update
      Stumbled upon this which has more than a couple of lines about BASH ':' COMMAND
      Last edited by Bogomips on 17 Apr 2016, 19:28, edited 1 time in total.
      Reason: More : info
      Linux porteus 4.4.0-porteus #3 SMP PREEMPT Sat Jan 23 07:01:55 UTC 2016 i686 AMD Sempron(tm) 140 Processor AuthenticAMD GNU/Linux
      NVIDIA Corporation C61 [GeForce 6150SE nForce 430] (rev a2) MemTotal: 901760 kB MemFree: 66752 kB

      Post Reply