116

Is there such a thing in bash or at least something similar (work-around) like forward declarations, well known in C / C++, for instance?

Or there is so such thing because for example it is always executed in one pass (line after line)?

If there are no forward declarations, what should I do to make my script easier to read. It is rather long and these function definitions at the beginning, mixed with global variables, make my script look ugly and hard to read / understand)? I am asking to learn some well-known / best practices for such cases.


For example:

# something like forward declaration
function func

# execution of the function
func

# definition of func
function func
{
    echo 123
}

3 Answers 3

223

No, bash does not have forward function declarations. I use a pattern like this for most of my scripts:

#!/bin/bash

main() {
    foo
    bar
    baz
}

foo() {
}

bar() {
}

baz() {
}

main "$@"

You can read the code from top to bottom, but it doesn't actually start executing until the last line. By passing "$@" to main() you can access the command-line arguments $1, $2, et al just as you normally would.

Sign up to request clarification or add additional context in comments.

4 Comments

Hi, how do you structure data that has to be shared between foo/bar/baz in your example? Usually I just put it at the top of the script. Is this still the case when using functions? Or is it better to put global data in main, and then pass it to foo/bar/baz as arguments? What's the best practice?
I prefer arguments. Barring that, I'll set global variables in main or in a function right after main (e.g., setup or parseArguments). I avoid having global variables set above main -- code should not go outside of main.
This seems somewhat analogous to what if _ _ name _ _ == "_ _ main _ _": main() does in python
This is also fantastic when using tools like Bats to test your scripts, breaking everything down into functions makes testing the individual components much easier. See also blog post
34

When my bash scripts grow too much, I use an include mechanism:

File allMyFunctions:

foo() {
}

bar() {
}

baz() {
}

File main:

#!/bin/bash

. allMyfunctions

foo
bar
baz

3 Comments

Personally, when a shell script starts growing past one file, I tend to switch to a different language ;-)
Wouldn't it be better to use source allMyfunctions?
@pydoge: source is not POSIX-compliant. bash defines source as an alias to .: they are functionally equivalent.
2

You can have the script source portions of itself:

#!/bin/bash
. <( sed -n '/^#SOURCE-BEGIN/,/^#SOURCE-END/{//!p;}' $0 )
greeting "$@"
foo hey

#SOURCE-BEGIN
greeting() {
  for i in "$@"
  do
    echo ">[$i]"
  done
}

foo() {
  echo in foo
  echo "arg passed in: $1"
}
#SOURCE-END

echo good bye
$ ./myscript.sh hello world "one string"
>[hello]
>[world]
>[one string]
in foo
arg passed in: hey
good bye

I used process substitution (<(....)) to source the output of the sed command. The sed syntax comes from here, search for What about the classic sed solution?

2 Comments

this is wild
Not sure to +1 or -1 this one. Nifty for sure, but a bit too smart.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.