How to Export and Pass Bash Arrays to Sub-shells and Child Scripts
Why Bash Arrays Can't Be Exported to Child Processes
In Bash, you might expect that combining the -g (global) and -x (export) flags with declare would allow you to share an array with a child script. However, when you run ./work.sh as a separate executable, it spawns a new sub-shell process.
Because environment variables are fundamentally restricted to flat, simple strings, Bash does not support exporting arrays to child processes. The export flag (-x) is effectively ignored for array variables when spawning external commands or scripts. Fortunately, there are several clean workarounds to achieve the desired behavior.
Solution 1: Source the Child Script (Simplest Approach)
If work.sh does not strictly need to run in a completely isolated process, the easiest solution is to source it. Sourcing runs the target script within the current shell context, giving it direct access to all defined variables and arrays without needing to export them.
Modify the end of your init.sh script like this:
# Instead of ./work.sh, source the script
source ./work.sh
# Or use the shortcut:
. ./work.shSolution 2: Pass the Array as Arguments
If you must run work.sh as an independent process, the most robust and standard way to share data is to pass the array elements as positional arguments.
Update init.sh to pass the array:
# Pass the array elements safely using double quotes
./work.sh "${BIRD_LIST[@]}"Then, update work.sh to read those arguments into a local array:
#!/bin/bash
list_birds() {
# Capture all arguments passed to the script into a local array
local BIRD_LIST=("$@")
local BIRDS_COUNT=0
echo "List of birds to check is: ${BIRD_LIST[*]}."
for BIRD in "${BIRD_LIST[@]}"; do
echo "The next bird is ${BIRD} ..."
((BIRDS_COUNT++))
done
echo "Info: Listed ${BIRDS_COUNT} birds."
}
# Pass the script's arguments directly to the function
list_birds "$@"Solution 3: Serialize and Deserialize the Array
If you cannot change the signature of how work.sh is called, you can serialize the array into a single string, export that string, and reconstruct the array inside the child script.
Update init.sh to export a space-separated string:
function init_env() {
declare -ag BIRD_LIST=("albatross" "blackbird" "crow" "dove")
# Serialize and export as a standard string
export BIRD_LIST_STR="${BIRD_LIST[*]}"
}
init_env
./work.shThen, update work.sh to reconstruct the array from the exported string:
#!/bin/bash
list_birds() {
# Reconstruct the array using read
local BIRD_LIST
read -r -a BIRD_LIST <<< "$BIRD_LIST_STR"
local BIRDS_COUNT=0
echo "List of birds to check is: ${BIRD_LIST[*]}."
for BIRD in "${BIRD_LIST[@]}"; do
echo "The next bird is ${BIRD} ..."
((BIRDS_COUNT++))
done
echo "Info: Listed ${BIRDS_COUNT} birds."
}
list_birdsSummary
While Bash prevents direct array exporting for security and structural reasons, using sourcing (Solution 1) or argument passing (Solution 2) are the most idiomatic and secure ways to share array data with sub-shells.