Array Manipulation
- elements.bsh
Set of -euE safe functions to make bash
array manipulation easy
Set of functions for deleting, prepending and appending without repetition. Versions using actual Bash
arrays are suffixed with an _a, else it works on delimiter (IFS) separated string
These functions use variable indirection when possible to make using them friendlier.
Note
Not intended for POSIX sh, works on bash and others like ksh
- dynamic_set_a
- Arguments:
$1
- Name of array to be set[
$2...
] - Values to set
Dynamically set an array to values from arguments
Example
dynamic_set_a my_array_name 11 "2 2" 33
# Is like executing
# my_array_name=(11 "2 2" 33)
- dynamic_set
- Arguments:
$1
- Name of variable to be set$2
- Value to set
Dynamically set a variable to a value. There are a number of properties that need to be preserved when setting a variable, export, local, global, etc… This method will allow you to indirectly set a variable while preserving these properties.
Example
dynamic_set my_name '11 "2 2" 33'
# Is like executing
# my_array_name='11 "2 2" 33'
- clear_a
- Arguments:
$1
- Name of array to be cleared- Output:
Returns
1
on invalid variable name
Slightly safer indirect clear array
Note
Still uses eval on older versions of bash, but makes sure the variable name appears valid
- remove_element_a
- Arguments:
$1
- Name of array to be set$2
- Value to be removed
Removes all instances of a value from an array
Example
x=(11 22 33 22 44)
remove_element_a x 22
# declare -a x='([0]="11" [1]="33" [2]="44")'
Note
The resulting array is sequentially indexed, which is not typical in bash
when removing elements from an array
- remove_element
- Arguments:
$1
- Name of string to be set$2
- String to be removed
- Parameters:
[
IFS
] - IFS Separator used
String version of remove_element_a
- add_elements_a
- Arguments:
$1
- Name of array to be set$2
… - Values to be appended
Just appends to array, allows repeats. ${1}+=("${@}")
- add_element_post_a
- Arguments:
$1
- Name of array to be set$2
- Value to be appended
Add a value to the end of an array
Removes all copies of the value from the array first, and then appends to the end of the array
Example
x=(22 11 22 33)
add_element_post_a x 22
declare -p x
# declare -a x='([0]="11" [1]="33" [2]="22")'
Note
The resulting array is sequentially indexed
- add_element_post
- Arguments:
$1
- Name of string to be set$2
- String to be appended
- Parameters:
[
IFS
] - IFS Separator used
String version of add_element_post_a
- add_element_pre_a
- Arguments:
$1
- Name of array to be set$2
- Value to be prepended
Add a value to the beginning of an array
Removes all copies of the value from the array first, and then prepends to the beginning of the array
Example
x=(11 22 33 22)
add_element_pre_a x 22
declare -p x
# declare -a x='([0]="22" [1]="11" [2]="33")'
Note
The resulting array is sequentially indexed
- add_element_pre
- Arguments:
$1
- Name of string to be set$2
- String to be prepended
- Parameters:
[
IFS
] - IFS Separator used
String version of add_element_post_a
- cmp_elements_a
- Arguments:
$1
- First array name$2
- Second array name
- Output:
Return Value:
0
- Identical,1
- Not identical
Checks if two arrays are the same
- cmp_elements
- Arguments:
$1
- First string name$2
- Second string name
- Output:
Return Value:
0
- Identical,1
- Not identical
String version of cmp_elements_a
- split_s
- Arguments:
$1
- Target array name$2
… - Strings
- Parameters:
[
MIFS
] - A Multicharacter Internal Field Separator.Default: //
Splits an string into an array, using an MIFS
Author
https://stackoverflow.com/a/47633817/4166604
- join_a
- Arguments:
$1
- Target string name$2
… - Array elements
- Parameters:
[
MIFS
] - A Multicharacter Internal Field Separator.Default: //
- Return Value:
0
- Success1
- No elements were provided. This is done to create a distinction betweenjoin_a x
andjoin_a x ""
.
Joins an array into a string, using an MIFS
Note
When 1
is returned, this is the only time the output is not compatible with split_s
.
- join_a_out
- Arguments:
$1
- Hex code for IFS$2
… - Strings
- Parameters:
[
MIFS
] - A Multicharacter Internal Field Separator, using awk escape format. (Except for null, which is a double backslash \x00).Default: //
Note: If you are using “” or $’’ notation, you will need “\\x00”
Instead of storing the value to a variable, this outputs to stdout. Unlike join_a
, join_a_out
can handle special characters, like null. Because macOS awk is so difficult, instead of ‘x00’ for null, use ‘\x00’. No other form of null will work on macOS. All other sed escape character should work.
Author
https://superuser.com/a/720157/352118
- is_array
- Arguments:
$1
- variable name
- Output:
Returns
0
if variable is an array, else1
Determines if $1
is an array or not. If it is not defined, still returns 1
- is_associative_array
- Arguments:
$1
- variable name
- Output:
Returns
0
if variable is an associative array, else1
Determines if $1
is an associative array or not. If it is not defined, still returns 1
- to_array
- Arguments:
$1
- variable name
Convert an string to an array, honoring quotes and newlines
$ x=$'11 "2\n2" "3 \t 3 " ""'
$ to_array x
$ declare -p x
declare -a x=([0]="11" [1]=$'2\n2' [2]=$'3 \t 3' [3]="")
Bugs
$ x='"f\o\\o" f\o\\o '\''f\o\\o'\'
$ eval "y=(${x})"
$ to_array x
$ declare -p x
$ declare -p y
declare -a x=([0]="f\\o\\\\o" [1]="fo\\o" [2]="f\\o\\\\o")
declare -a y=([0]="f\\o\\o" [1]="fo\\o" [2]="f\\o\\\\o")
# Only the double backslash in double quotes comes out wrong, due to a bug in xargs? To get around this bug, use ``eval`` instead
- array_length
- Arguments:
$1
- Array name
- Output:
stdout - number of elements in the array. -1 for variable not defined.
Echoes out the length of the array. If the variable is not defined, echos -1.
Note
Does not differentiate between an array of length 1 and a non-array variable. Use is_array
for that
- subtract_array
- Arguments:
$1
- Array 1$2
- Array 2$3
- Destination Array
Destination array becomes values of array 2 not in array 1 (1 - 2). The destination array name can be the same as Array 1 or 2.
- array_to_variable
- Arguments:
$1
- Array name$2
- Variable name prefix
Converts an array to a set of variables, starting with the prefix ${2}_
numbered from 1 to N in sequential order, even if there are holes in the array.
- variables_to_array
- Arguments:
$1
- Variable name prefix$2
- Array name
Converts a set of variables to an array, starting with the prefix ${1}_
numbered from 1 to N in sequential order, stops as soon as one does not exist.
Note
Will not detect variables that are declared but unassigned, will work with variables set to null.
- all_variables_to_array
Same as variables_to_array
, but can skip indexing numbers
See also
variables_to_array
Sequential only version of function
- serialize_array
Serializes an array (or associative array in bash 4 or newer) into a single string
- Arguments:
$1
- Name of array- Output:
stdout - The serialized string representing the array
Handles any array, all special characters without issue, for both key and value, except NULL
which isn’t allowed in any bash variable anyways. However, the results will not differentiate between an unassigned array and an empty array.
An array is converted to a string using the following schema
Array
"a" + (index0 + " " + length_of_value0 + " " + value0) + (index1 + ...
Associative Array
"A" + (length_of_key0 + " " + key0 + length_of_value0 + " " + value0) + ...
Example
x=(11 22 33)
unset x[1]
y="$(serialize_array x)"
# "a0 2 112 2 33"
deserialize_array x2 "${y}"
# x and x2 are identical
See also
- deserialize_array
Convert a serialized array (string) into an array or associative array.
- Arguments:
$1
- Output variable name$2
- Serialized string
If you do not declare the output variable before calling deserialize_array
, it will attempt to create it. This works pretty well for indexed arrays, but associative arrays are trickier. On bash 4.2 or newer, it will create it as a global variable if it is not already defined as an associative array. This makes controlling the scope difficult and does not work in older versions of bash. It’s best to define the variable before calling, if possible.
See also