Functions (Bash)

Uit De Vliegende Brigade
Naar navigatie springen Naar zoeken springen

Bash knows functions. These often seem to be considered full implementations of the concept of subroutines.

Declare first

A function must be declared before being called: The declaration must be earlier in the script than the part calling it.

Scope

Variables are by default global, so functions could be a nice replacement for subroutines, because they are debuggable.

  • However, when variables are declared using the declare command, they get local scope. Use the -g flag to make them global
  • Stuff gets more complicated when calling a function involves a subshell. See Subshells (Bash) for details.

Why use functions?

What I think in general is the usefulness of functions:

  • Clustering of related code
  • Flow control, in particular: preventing repeating code
  • Reuse: Around the age of 13 I learned the concept of libraries and that has always appealed to me. In recent years my library (mainly SQL sprocs) has actually become a production tool of mine, albeit of a limited size
  • Abstraction: At certain times you can concern yourself with what functions do, without having to know exactly how it is done.

Basis

[1]:

  • POSIX-syntaxis voor functies: fn_name () compound-command [ redirections ]
  • Alternatieve Bash-syntaxis: function fn_name [()] compound-command [ redirections ].
  • The exit status of a function definition is zero (success) unless another read-only function with a similar name already exists or a syntax error occurs
  • Functies kunnen ook in direct mode in Bash toegepast worden.

Voorbeeld:

$ mijnfunctie() { echo "Hello, world!"; }
$ mijnfunctie
Hello, world!

[2]:

⚠️ When using the curly braces {} notation, make sure to separate the content 
of the function and the braces with blanks or newlines, otherwise, a syntax 
error near unexpected token will be raised. This is due to historical reasons 
as the braces are reserved words and can only be recognized as such when they 
are separated from the command list by whitespace or another shell 
metacharacter. Also when using the braces notation, you must terminate the 
last command by a semi-colon ;, an ampersand &, or a newline.

No argument passing with ()

The () after the function name, is in most languages used for argument passing. In Bash, () are purely decorative. They have no function

Actual argument passing

Contrary to what was written in the previous chapter, there is such a thing as argument passing. It works the same way as for Bash scripts: Just add the arguments in the call, and retrieve them inside the function with $1, $2, etc.

Return values

  • With Bash functions, you can't return specific values, as you can in many other languages
  • You can however, return a status. Within the calling environment, this is available through variable $. Usually, a return value of 0 indicates success.

Return value

How to use Bash functions, ehm, as functions? Meaning that they return someting, based on the input?

Simple: Capture the return of a command, like in chaining. Example:

mytestfunction()
{
   # Just return input argument
   echo $1
}

$ returnvalue=`mytestfunction "Hello, world!"`
$ echo $returnvalue

Hello, world!

$ returnvalue=$(mytestfunction "Hello, world!")
$ echo $returnvalue

Hello, world!

Multiple arguments in one variable

Case

Case: Using WP-CLI, I want to translate hierarchical ACM fields. Example:

Original statement:

wp option patch update options_footer_links_3_7_link url 	"$options_footer_links_3_7_link__url"

I would like to change that to something like

wp option patch $entity $value

where $entity would consist of the entities: options_footer_links_3_7_link url (these are two objects - Note the space).

The WP-CLI is probably mostly written in PHP with a Bash shell around it. Nevertheless, let's see how this stuff works in Bash - This might be mostly about Bash syntaxis

Test

#
# Location: O&O » Bash » functions-and-arguments.sh
#
# testfunction()
########################################
#
testfunction()
{
   echo "testfunction(). Arguments: 1: $1,	2: $2,	3: $3"
}


# Main
########################################
#
arg1='"een" "twee" "drie"'
arg2='een twee drie'
arg3="een twee drie"

echo "With three separate arguments (without double quotes)"       # OK
testfunction een twee drie

echo "With three separate arguments (each within double quotes)"   # OK
testfunction "een" "twee" "drie"

echo "With arg1: "; testfunction $arg1   # OK
echo "With arg2: "; testfunction $arg2   # OK
echo "With arg3: "; testfunction $arg3   # OK

echo "With arg1 (double quotes): "; testfunction "$arg1"
echo "With arg2 (double quotes): "; testfunction "$arg2"
echo "With arg3 (double quotes): "; testfunction "$arg3"

Outcomes (reformatted):

With three separate arguments (without double quotes) testfunction(). Arguments: 1: een,	2: twee,	3: drie
With three separate arguments (each within double quotes) testfunction(). Arguments: 1: een,	2: twee,	3: drie

With arg1: testfunction(). Arguments: 1: "een",	2: "twee",	3: "drie"   # OK, although not as intended
With arg2: testfunction(). Arguments: 1: een,	2: twee,	3: drie     # OK
With arg3: testfunction(). Arguments: 1: een,	2: twee,	3: drie     # OK

With arg1 (double quotes): testfunction(). Arguments: 1: "een" "twee" "drie",	2: ,	3:   # Not OK
With arg2 (double quotes): testfunction(). Arguments: 1: een twee drie,	2: ,	3:           # Not OK
With arg3 (double quotes): testfunction(). Arguments: 1: een twee drie,	2: ,	3:           # Not OK

See also

Sources