Skip to content

Instantly share code, notes, and snippets.

@dakkar
Created June 11, 2014 16:38
Show Gist options
  • Save dakkar/1cb349834f6b144255be to your computer and use it in GitHub Desktop.
Save dakkar/1cb349834f6b144255be to your computer and use it in GitHub Desktop.
Dealing with arrays in bash
#!/bin/bash
# this is *complicated*
#
# we want to be able to set an array to the value of another
# array. this is harder than it should be
#
# The call:
# _set_array foo 1 "2 3" "4 5 6"
# should execute:
# foo=(1 "2 3" "4 5 6")
#
# the only way to get 'foo' on the LHS of the assignment is within an
# eval, but at that point we need to escape the rest of the parameters
# to avoid losing information
#
# 'declare -p foo' prints a properly-escaped expression that, when
# eval-ed, will assign to foo its current value
#
# so:
function _set_array() {
# take the name of teh destination array
local _sa_varname="$1"
shift
# copy the rest of the arguments to a local array we can call by
# name ("declare -p @" doesn't work, $@ is magical)
local -a _private_name_=("$@")
# get the declare string
local _sa_assignment="$(declare -p _private_name_)"
# remove the parts we don't want
_sa_assignment="${_sa_assignment#declare -a _private_name_=\'}"
_sa_assignment="${_sa_assignment%\'}"
# put in the assignment to the destination array
_sa_assignment="$_sa_varname=$_sa_assignment"
# eval the whole thing
eval "$_sa_assignment"
}
# there may be a simpler way, but I couldn't find it
# example of function that "returns" an array:
# find_files_in_array $name_of_array $option_to_find $more_option_to_find
function find_files_in_array() {
# get the name of the destination array
local _ffia_varname="$1"
shift # and remove it from $@
# local variables: I prefix their names because they may conflict
# with the name of the destination array, in which case the 'eval'
# is _set_array will assign to the *local* variablems :(((
local -a _ffia_files
local _ffia_file
# "simple" read from stdin and accumulate in array; we can't use a
# pipe, because in that case the 'while' would run in a separate
# process, and we'd lose its variables
while read -r -d $'\0' _ffia_file; do
_ffia_files+=("$_ffia_file")
done < <(find . -type f "$@" -print0)
# finally, assign the result to the destination array
_set_array "$_ffia_varname" "${_ffia_files[@]}"
}
# and here is how to use it
function print_files() {
# declare a variable
local -a files
# fill it with file names
find_files_in_array files -name 'foo*'
# print each file name
local f
for f in "${files[@]}"; do
echo "> $f"
done
}
print_files
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment