Does bash provide support for using pointers?
A pointer (to a location of memory) is not really a useful concept in anything higher-level than C, be it something like Python or the shell. References to objects are of course useful in high-level languages, perhaps even necessary for building complex data structures. But in most cases thinking in terms of memory addresses is too low level to be very useful.
In Bash (and other shells), you can get the values of array elements with the ${array[index]}
notation, assign them with array[index]=...
and get the number of elements in the array with ${#array[@]}
. The expression inside the brackets is an arithmetic expression. As a made-up example, we could add a constant prefix to all array members:
for ((i=0 ; i < ${#array[@]} ; i++ )) ; do
array[i]="foo-${array[i]}"
done
(If we only cared about the values, and not the indexes, just for x in "${array[@]}" ; do...
would be fine.)
With associative or sparse arrays, a numerical loop doesn't make much sense, but instead we'd need to fetch the array keys/indexes with ${!array[@]}
. E.g.
declare -A assoc=([foo]="123" [bar]="456")
for i in "${!assoc[@]}" ; do
echo "${assoc[$i]}"
done
In addition to that, Bash has two ways to point indirectly to another variable:
- indirect expansion, using the
${!var}
syntax, which uses the value of the variable whose name is invar
, and - namerefs, which need to be created with the
declare
builtin (or theksh
-compatible synonym,typeset
).declare -n ref=var
makesref
a reference to the variablevar
.
Namerefs also support indexing, in that if we have arr=(a b c); declare -n ref=arr;
then ${ref[1]}
will expand to b
. Using ${!p[1]}
would instead take p
as an array, and refer to the variable named by its second element.
In Bash, namerefs are literally that, references by name, and using a nameref from inside a function will use the local value of the named variable. This will print local value of var
.
#!/bin/bash
fun() {
local var="local value of var"
echo "$ref";
}
var="global var"
declare -n ref=var
fun
BashFAQ has a longer article on indirection, too.
No, bash
doesn't have "pointers", but it does have references:
$ spam="fred"
$ declare -n tripe=spam
$ echo $tripe
fred
$ tripe=juki
$ echo $spam
juki
From the bash
man page:
A variable can be assigned the nameref attribute using the -n option to the
declare
orlocal
builtin commands to create a nameref, or a reference to another variable. This allows variables to be manipulated indirectly. Whenever the nameref variable is referenced, assigned to, unset, or has its attributes modified (other than using or changing the nameref attribute itself), the operation is actually performed on the variable specified by the nameref variable's value. A nameref is commonly used within shell functions to refer to a variable whose name is passed as an argument to the function. For instance, if a variable name is passed to a shell function as its first argument, runningdeclare -n ref=$1
inside the function creates a nameref variable ref whose value is the variable name passed as the first argument. References and assignments to ref, and changes to its attributes, are treated as references, assignments, and attribute modifications to the variable whose name was passed as $1. If the control variable in a for loop has the nameref attribute, the list of words can be a list of shell variables, and a name reference will be established for each word in the list, in turn, when the loop is executed. Array variables cannot be given the nameref attribute. However, nameref variables can reference array variables and subscripted array variables. Namerefs can be unset using the -n option to the
unset
builtin. Otherwise, ifunset
is executed with the name of a nameref variable as an argument, the variable referenced by the nameref variable will be unset.
No, shells do not use "pointers" (as understood in C).
Arrays could use indices: echo "${array[2]}"
but the @
in your example is not really a "pointer". It is a way to express "the list of array values". Something that the shell parser understand. Similar to the way a:
$ echo "$@"
expands to all the "Positional Parameters" list.