Bash Parameters and Variables: Difference between revisions
Line 33: | Line 33: | ||
Positional parameters are assigned from the shell’s arguments when it is invoked. | Positional parameters are assigned from the shell’s arguments when it is invoked. They may not be assigned to with assignment statements, but they can be reassigned with [[Bash_set#set_and_Positional_Parameters|set]] builtin command and they can be shifted left with the bash built-in command [[bash shift|shift]]. | ||
The positional parameters are temporarily replaced when a shell function is executed (see Shell Functions). | The positional parameters are temporarily replaced when a shell function is executed (see Shell Functions). | ||
==Iterating over Positional Paramenters== | ==Iterating over Positional Paramenters== |
Revision as of 20:37, 18 September 2019
Internal
Parameters and Variables
Shell stores values internally using entities named parameters.
Parameters can be designated by a number (e.g. 1), a special character (e.g. *), or a name (e.g. blue). Parameters designated by a name are referred to as variables. The variables that have a special meaning to the shell (for example "IFS") are known as internal or built-in variables.
Non-variable parameters can be further categorized in positional parameters, which are the shell's command line arguments, retrievable as $1, $2, etc. and special parameters, that are denoted by special characters.
Accessing a Parameter's or Variable's Value
For both parameters and variables, the associated value is retrieved by prefixing the parameter/variable's number, character or name with $ or enclosing it in ${...}
Difference between $ and ${...}
Positional Parameters $1, $2, ...
A positional parameter is a parameter denoted by one or more digits, other than the single digit 0 (the single digit 0 denotes the special parameter $0).
bash allows only nine parameters to be referenced directly (n = 1–9) as in:
$1
$1 is equivalent with ${1}.
When a positional parameter consisting of more than a single digit is expanded, it must be enclosed in braces. For n values greater than 9, the command line arguments must be specified as ${n}:
${10}
Positional parameters are assigned from the shell’s arguments when it is invoked. They may not be assigned to with assignment statements, but they can be reassigned with set builtin command and they can be shifted left with the bash built-in command shift.
The positional parameters are temporarily replaced when a shell function is executed (see Shell Functions).
Iterating over Positional Paramenters
Solution 1
while [ -n "$1" ]; do ... shift done
Solution 2
Special Parameters
$0
The name of the shell or shell script. This will have the full pathname if it was found via a PATH search.
Variables
Built-in Variables
Parameter and Variable Expansion
A dollar sign ($) that is NOT followed by an open parenthesis initiates parameter or variable expansion.
Parameters include:
- Command line (positional) parameters: $1, $2, ...
- Special parameters:
Variables include:
- User-created variables
- Keyword variables
Parameters and variables are not expanded if the string they are included in are enclosed within single quotes or if the leading dollar sign is escaped. Parameters and variables are expanded if the string they are included in is enclosed within double quotes.
Parameter and variable expansion is a particular case of bash command line expansion:
Expand to a Default Value
${var:-alternative}
The :- form : if the variable 'var' referred in the expression was not defined, or it is the empty string, the expression expands the alternative.
${var-alternative}
The - form: if the colon is omitted, the expression is expanded to the alternative value only if the variable is not defined, not when it was empty.
Assign a Default Value
${var:=word}
${var=word}
This expression works like expansion to a default value, but the word is not only expanded, but also assigned to the variable, if it was unset or null. The first form work if the variable is unset or an empty string, the second only if the parameter was unset.
Use an Alternate Value
${var:+alternative}
This form expands to nothing if the parameter is unset or empty.
${var+alternative}
This form expands to nothing if the variable is unset, and to the alternative if the variable is empty.
Variable Expansion in an Arbitrary File
If an arbitrary text file contains environment variable declarations, they can be expanded with envsubst. No other shell command line expansions will be performed. More details:
String Length
The length of a variable's value:
${#var}
$!... Variable Indirection, Indirect Expansion
If the first character of parameter is an exclamation point (!), a level of variable indirection is introduced. Bash uses the value of the variable formed from the rest of parameter as the name of the variable; this variable is then expanded and that value is used in the rest of the substitution, rather than the value of parameter itself. This is known as indirect expansion. The exceptions to this are the expansions of ${!prefix*} and ${!name[@]} described below. The exclamation point must immediately follow immediately after the left brace in order to introduce indirection. Example:
a="b" b="blah" echo ${!a}
produces "blah".
Note that assigning a value to a indirect variable does not need to use "${!...}". For the above example, we can simply:
${a}=blah
This will assign "blah" to a variable named "b".
In each of the cases below, word is subject to tilde expansion, parameter expansion, command substitution, and arithmetic expansion.
When not performing substring expansion, using the forms documented below, bash tests for a parameter that is unset or null. Omitting the colon results in a test only for a parameter that is unset.
Undeclared Variable
An undeclared variable is equivalent with an empty string when referenced. There is no error when such a variable is referenced in a bash program:
echo ">${no_such_var}<" ><
Uninitialized Variable
An uninitialized variable is equivalent with an empty string when referenced. There is no error when such a variable is referenced in a bash program:
local some_var echo ">${some_var}<" ><
Global Variable
Global variables are only maintained within the context of the current shell. Once the shell exits, the global variables are discarded.
The global variables declared in a shell are visible inside the functions executed within that shell and inside functions invoked from function invoked from the shell, recursively.
The value of a global variable is not available to sub-shells, unless the variable is exported, with the #export keyword.
export
export VAR=VALUE
Declaring a global variable to be exported causes the variable and its value to be copied in the environment of a sub-shell. The sub-shell gets a copy of the variable, not a reference. The sub-shell has no access to the parent process's environment whatsoever. Modifying the variable from the sub-shell does not reflect into the value of the global variable maintained by the invoking shell. When the shell sub-process terminates any changes made to its environment are lost. There is no way to modify directly the parent's environment.
Variables exported by Sub-Shells
If a sub-shell invoked from another shell exports a global variable, once the sub-shell exits, the exported variables are discarded, and the invoking shell does not sees them.
Local Variable
If a variable is declared inside a function, without any qualifier, it automatically becomes a global variable, and it is visible to the entire shell after the function execution, even after the function exits.
In order to prevent a variable declared inside of a function to become global, it must be declared as local: the local keyword designates a local variable. Local variables can only be declared inside a function.
Example:
local a=b
Local Variable Assignment and Failure
Do not do a local variable assignment from a function that may return non-zero and expect to use the return value to exit
Do not do something like this:
local a=$(do_something) || exit 1 # hoping to exit if 'do_something' returns a non-zero value
Even if do_something returns a non-zero error code, that is not detected and exit is not executed.
Do this instead:
local a; a=$(do_something) || exit
Listing Declared Variables
declare -p
A way of obtaining the value for a specific variable is:
local var_name="HISTSIZE" declare -p | grep "declare .. ${var_name}" | sed -e 's/.*=//'
Booleans
Recommended usage pattern:
Declaration:
some_var=true
Usage:
${some_var} && echo "this will execute" if ${some_var}; then echo "this will execute" fi
Do not use:
if [ ${some_var} ]; then ...
This will always evaluate to "true" regardless of the some_var value.