bash: functionsFunctions: name a block, pass arguments, return a status
A function gives a name to a group of commands so a script can reuse them: log, die, retry, check_disk. It takes arguments like a script ($1, $@), returns an exit status (0-255) rather than a value, hands back data by printing it, and should keep its working variables local.
name() { commands; } name arg1 arg2 local var=value return [N] out=$(name)A pre-deploy script should print timestamped messages, retry a flaky check a few times and stop with a clear error.
retry()Defines a function called retry. The () is always empty: arguments are not declared, they arrive as $1, $2...
Defining a function stores its parsed body in the shell's function table; nothing runs until the name is called, and bash looks up a word as alias, then function, then builtin, then a program in PATH. So a function must be defined before the line that calls it executes. A call runs in the current shell process, not a child: no fork, no exec, so it can change global variables, cd, and set traps. Bash temporarily replaces the positional parameters $1..$9, $# and $@ with the call's arguments ($0 stays the script name; FUNCNAME holds the function's). local creates a variable with dynamic scope: visible in this function and in functions it calls, restored when it returns. return N ends the call and sets $? to N modulo 256; without it the status is that of the last command. Data comes back through stdout, captured by $(name), which runs the function in a forked subshell, so any variables it sets there are lost.
name() { ...; }Define a function (the POSIX form; 'function name { }' is bash-only)name a bCall it like a command; inside, the arguments are $1, $2, $@ and $#local v=xVariable that exists only during this call (and functions it calls)return NLeave with exit status N (0-255); default: status of last commandout=$(name)Capture what the function prints: the way to 'return' dataif name; thenBranch on the function's exit status, like any command"$@"All arguments, each kept as one word: forward them to another commanddeclare -f namePrint a function's definition (declare -F lists names only)type nameShow whether a name is a function, builtin, alias or fileexport -f nameMake a function available to child bash processesunset -f nameDelete a function definitionadd() { return $(( $1 + $2 )); }; add 200 100; echo $?return sets a one-byte status: 300 comes back as 44. It is not a way to return numbers or strings.
add() { echo $(( $1 + $2 )); }; sum=$(add 200 100)Using i, file or count inside a helper without localFunction variables are global by default; a helper's loop counter can silently change the caller's loop.
local i file countlocal out=$(some_command); if [ $? -ne 0 ]; then ...$? is now the status of local itself, which is always 0, so the failure is hidden.
local out; out=$(some_command) || return 1run() { $* ; }Unquoted $* re-splits arguments, so a file named 'weekly report.txt' becomes two arguments.
run() { "$@"; }Calling a function before the line that defines itBash runs scripts top to bottom; the name doesn't exist yet: 'command not found'.
Functions first, then main "$@" at the bottomTry these on a Linux machine of your own. Each task has a hint and a solution.
Write a function greet that prints 'Hello, NAME' for its first argument, and call it with your user name.
Write a function count_errors that prints the number of ERROR lines in the file given as its argument, and store the result for ~/logs/app.log in a variable.
Write a function is_root that returns success only when run as root, and use it in an if.
Show that a variable set without local inside a function changes the global one, and that local doesn't.
bash: functionsFunctions: name a block, pass arguments, return a status
A function gives a name to a group of commands so a script can reuse them: log, die, retry, check_disk. It takes arguments like a script ($1, $@), returns an exit status (0-255) rather than a value, hands back data by printing it, and should keep its working variables local.
name() { commands; } name arg1 arg2 local var=value return [N] out=$(name)A pre-deploy script should print timestamped messages, retry a flaky check a few times and stop with a clear error.
retry()Defines a function called retry. The () is always empty: arguments are not declared, they arrive as $1, $2...
Defining a function stores its parsed body in the shell's function table; nothing runs until the name is called, and bash looks up a word as alias, then function, then builtin, then a program in PATH. So a function must be defined before the line that calls it executes. A call runs in the current shell process, not a child: no fork, no exec, so it can change global variables, cd, and set traps. Bash temporarily replaces the positional parameters $1..$9, $# and $@ with the call's arguments ($0 stays the script name; FUNCNAME holds the function's). local creates a variable with dynamic scope: visible in this function and in functions it calls, restored when it returns. return N ends the call and sets $? to N modulo 256; without it the status is that of the last command. Data comes back through stdout, captured by $(name), which runs the function in a forked subshell, so any variables it sets there are lost.
name() { ...; }Define a function (the POSIX form; 'function name { }' is bash-only)name a bCall it like a command; inside, the arguments are $1, $2, $@ and $#local v=xVariable that exists only during this call (and functions it calls)return NLeave with exit status N (0-255); default: status of last commandout=$(name)Capture what the function prints: the way to 'return' dataif name; thenBranch on the function's exit status, like any command"$@"All arguments, each kept as one word: forward them to another commanddeclare -f namePrint a function's definition (declare -F lists names only)type nameShow whether a name is a function, builtin, alias or fileexport -f nameMake a function available to child bash processesunset -f nameDelete a function definitionadd() { return $(( $1 + $2 )); }; add 200 100; echo $?return sets a one-byte status: 300 comes back as 44. It is not a way to return numbers or strings.
add() { echo $(( $1 + $2 )); }; sum=$(add 200 100)Using i, file or count inside a helper without localFunction variables are global by default; a helper's loop counter can silently change the caller's loop.
local i file countlocal out=$(some_command); if [ $? -ne 0 ]; then ...$? is now the status of local itself, which is always 0, so the failure is hidden.
local out; out=$(some_command) || return 1run() { $* ; }Unquoted $* re-splits arguments, so a file named 'weekly report.txt' becomes two arguments.
run() { "$@"; }Calling a function before the line that defines itBash runs scripts top to bottom; the name doesn't exist yet: 'command not found'.
Functions first, then main "$@" at the bottomTry these on a Linux machine of your own. Each task has a hint and a solution.
Write a function greet that prints 'Hello, NAME' for its first argument, and call it with your user name.
Write a function count_errors that prints the number of ERROR lines in the file given as its argument, and store the result for ~/logs/app.log in a variable.
Write a function is_root that returns success only when run as root, and use it in an if.
Show that a variable set without local inside a function changes the global one, and that local doesn't.