Bash – Writing a script containing just one function definition v.s. moving the code in function body to the script

bashfunctionscripting

Some background: When writing reusable code in bash, I saw some shell scripts containing several definitions of functions. Sometimes I can't figure out if the functions defined in a script are related, or the script is actually a mess, or I don't know how to organize multiple functions in one script yet (what are your tips for that purpose?). So I am thinking of writing a script containing just one function definition, and I am guessing I will have to organize multiple files. Which one is better, organizing multiple function definitions in one script or organizing multiple script files each with one function definition?

In the following, I will assume only writing a script containing just one function definition.


My actual questions start from here:

When writing a script containing just one function definition, I can write

#! /bin/bash

function myfunc() {
    echo $1, $2, $3
    # do some work...
}

and then I can use it by

source /path/to/myscript
myfunc 1 2 3

Alternatively, can I achieve the same goal of code reusability, by eliminating the function definition and moving the code in the function body to the script:

#! /bin/bash

echo $1, $2, $3
# do some work...

and then I can use it by

source /path/to/myscript 1 2 3

? The second way looks more concise than the first way in terms of both script content and usage, but I am not sure if someone may dislike the second way for some good reason.
I was wondering what some advantages and disadvantages of the above two ways are? What is your recommendation in practice?

If you use the first way in practice, would you name your script the same as your function, i.e. if your script containing a function named myfunc, do you name the script as myfunc too?

Thanks.

Best Answer

I do both depending on the circumstance. For most cases I will declare the functions in the same script that will be using them, however I do have a "toolkit" of scripts that has a file of variables and functions to be shared between all the scripts.

To Function or Not to Function

The main purpose of a function is DRY (Don't repeat yourself). If you have some code that will be used more than once in your script it should be in a function.

Using functions on non-repeating code is a matter of preference. Some people (myself included) consider it to be more neat. Additionally I think it closer resembles the way "real" programming languages are used.

Google's Shell Style Guide states that if your code contains at least one function you should use a "main" function as a wrapper for all your code. (Essentially your script will only be a series of function declarations ending with a single call to main)

Declaring functions (or writing code) inside of a single script

  • Simple (Anyone looking at the code will be able to easier track down what each function does)
  • Increases portability (Only one file needs to be moved from system to system)

If you are writing a stand alone script to perform a single task this is probably the way to go.

Declaring functions inside of a separate file

  • DRY (Don't repeat yourself)
  • Can be easier to manage

If you are creating a set of tools that share a lot of common functions this is likely the way to go.

In my example I have functions that are used by all or at least most of the scripts in the toolkit. This includes some functions that query our inventory management system and return information about servers such as IP address, OS version, etc. This information is useful for many of the tools so it makes sense to declare such functions in one file instead of all of the files individually. Additionally we recently made changes to the inventory management system, so instead of having to change 10+ different files I only had to change the common file to query the new system, the other files still work properly without modification.

Some disadvantages of this is that it is more complex. Each file has the following statement to source this common file:

if [[ -f "${0%/*}/lib/common.sh" ]]; then
    . "${0%/*}/lib/common.sh"
else
    echo "Error! lib/common.sh not found!"
    exit 1
fi

If users grab the toolkit and modify the directory structure or don't grab the entire directory structure the tools will not work as intended because they will be unable to source the common file.