Summary
This incident stemmed from a Bash script that attempted to populate an array with Docker container names but always produced an empty array. The script printed the names correctly inside the loop, yet the array remained empty afterward. The underlying issue was not Docker, not awk, and not array syntax — it was process substitution and subshell behavior.
Root Cause
The root cause was using a pipeline (| while read ...), which causes the while loop to run inside a subshell.
Arrays modified inside a subshell do not propagate back to the parent shell.
Key points:
docker ps -a | ... | while read psspawns a subshellcontainers+=("$name")happens inside that subshell- When the loop ends, the subshell exits and the parent shell’s array is unchanged
Why This Happens in Real Systems
This is a classic Bash pitfall because:
- Pipelines implicitly fork subshells
- Variables modified in subshells are not shared with the parent
- Bash does not warn you about this behavior
- Many engineers assume loops behave like in other languages
Real-World Impact
This bug can cause:
- Empty arrays when processing command output
- Lost state when building lists or counters
- Silent failures that are hard to debug
- Incorrect automation behavior in CI/CD or production scripts
Example or Code (if necessary and relevant)
A correct version avoids the pipeline and feeds input directly into the loop:
#!/bin/bash
containers=()
while read -r ps; do
inspect="$(docker inspect "$ps")"
name="$(echo "$inspect" | grep "Name" | head -n 1 | sed 's/.*: //' | sed 's_"/__' | sed 's/",//')"
containers+=("$name")
done < <(docker ps -a | awk '$1 != "CONTAINER" {print $1}')
echo "${#containers[@]}"
echo "${containers[@]}"
This works because process substitution does not create a subshell for the loop itself.
How Senior Engineers Fix It
Experienced engineers typically apply one of these patterns:
- Use process substitution instead of pipelines
while read ...; do ...; done < <(command) - Avoid subshells when state must persist
- Refactor loops to avoid unnecessary pipes
- Use
mapfilefor simple list ingestion - Prefer structured JSON output from Docker (
docker ps --format,docker inspect --format)
Why Juniors Miss It
Juniors often miss this issue because:
- They assume pipelines behave like in other languages
- They don’t know Bash silently forks subshells
- They see the loop printing correct values and assume the array must be filling
- Bash’s scoping rules are unintuitive and poorly documented
- They haven’t yet internalized the difference between:
- Pipelines (subshell)
- Redirection / process substitution (no subshell for the loop)
This is one of those classic Bash traps that every engineer eventually learns the hard way.