Shell数组遍历需用"${array[@]}"安全处理含空格文件名,避免"${array[*]}"导致分词错误;读取主机列表应优先用while read构建数组;动态生成推荐glob扩展或find+mapfile组合。

Shell数组遍历不是简单套用for循环,关键在于选对访问方式、避开空格陷阱、适配数据来源。处理文件列表和主机列表这两类高频场景,方法差异明显,但核心都围绕“安全”和“可控”展开。
用 ${array[@]} 遍历文件名数组,别用 ${array[*]}
当数组元素是带空格或特殊字符的文件路径(如 my report.pdf 或 log-2024-06-19.txt)时,必须用双引号包裹 ${array[@]},否则 shell 会把空格当分词符,导致命令误执行。
- ${array[@]}:每个元素独立成项,保持原始完整性
- ${array[*]}:所有元素拼成单个字符串,中间用第一个 IFS 字符(默认空格)连接,极易出错
正确写法示例:
files=("report final.pdf" "config_v2.json" "data (backup).csv")
for f in "${files[@]}"; do
ls -l "$f"
done从文件读取主机列表时,优先用 while + read 构建数组
/etc/hosts、hosts.txt 这类文本每行一个主机名,直接用 for host in $(cat hosts.txt) 会崩——遇到含空格的行(如 192.168.1.100 db-prod # primary)会被截断或跳过注释。
更健壮的做法是用 while read 逐行读取并赋值到数组:
hosts=()
while IFS= read -r line; do
[[ -n "$line" && "$line" != "#"* ]] && hosts+=("$line")
done < hosts.txt之后再用下标遍历,确保顺序和内容准确:
for i in "${!hosts[@]}"; do
echo "[$i] ${hosts[i]}"
done批量 SSH 操作:数组遍历 + 超时与非交互控制
单纯循环调用 ssh 容易卡死或漏执行。结合数组遍历时,必须加两项关键选项:
- -o ConnectTimeout=3:连接超时 3 秒,避免某台主机宕机拖垮整个流程
- -o BatchMode=yes:禁止交互式提示(如 password:),只依赖密钥登录
完整示例(检查多台主机磁盘使用率):
hosts=("web01" "db01" "cache01")
for host in "${hosts[@]}"; do
if ssh -o ConnectTimeout=3 -o BatchMode=yes "$host" 'df -h / | tail -1' 2>/dev/null; then
echo "✅ $host ok"
else
echo "❌ $host failed or unreachable"
fi
done动态生成数组:用 glob 或 find -print0 安全捕获文件
不要用 files=($(ls *.log)) —— 文件名含空格时会裂开。推荐两种安全方式:
-
Glob 直接扩展(最简):
logs=(*.log),前提是当前目录有匹配文件(可加shopt -s nullglob防空数组) -
find + mapfile(最稳):
mapfile -t logs < <(find /var/log -name "*.log" -print0 | xargs -0 printf '%s\n')
之后统一用 "${logs[@]}" 遍历,全程不触碰未加引号的变量展开。

















