Functions (Bash)
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
- https://ryanstutorials.net/bash-scripting-tutorial/bash-functions.php
- https://www.shell-tips.com/bash/functions/
- https://opensource.com/article/20/6/bash-functions
- https://linuxize.com/post/bash-functions
- https://tldp.org/HOWTO/Bash-Prog-Intro-HOWTO-8.html
- https://tldp.org/LDP/abs/html/functions.html