ZSH中FOR循环处理多行字符串的行为差异解析
三种Shell遍历写法的行为差异解析
1. 直接在for循环中使用命令替换
for CLOUD in $(jq -r '.clouds[].cloud_name' publicClouds.json) do echo "> $CLOUD" done
这种写法会逐个输出每个云服务商的名称,每个占一行。
原因很直白:Shell执行$(jq ...)拿到输出后,会自动按空格、换行、制表符(默认的IFS分隔符)拆分成独立片段,每个片段对应一个云名称。for循环会挨个遍历这些片段,所以每次循环只处理一个名称,输出符合预期。
2. 将结果存入普通变量后遍历
CLOUDS=$(jq -r '.clouds[].cloud_name' publicClouds.json) for CLOUD in "$CLOUDS" do echo "> $CLOUD" done
这种写法会把所有云名称一次性输出在同一个>后面,换行只是变量里原本带的格式。
- 普通变量
CLOUDS存的是命令输出的完整内容,包括所有换行符,相当于把所有云名称“打包”成了一个整体字符串。 - 用双引号
"$CLOUDS"包裹变量时,Shell会原封不动地把这个“打包字符串”当作单个元素,for循环只会执行一次,自然一次性输出所有内容。 - 要是去掉引号写
for CLOUD in $CLOUDS,Shell会再次拆分字符串,看起来能正常遍历,但这是碰运气——如果某个云名称带空格(比如"AWS US East"),就会被拆成两个片段,遍历直接出错。
至于wc -l <<< $CLOUDS返回103,是因为<<<会把变量里的原始内容(包括所有换行符)传给wc -l,统计的就是变量内的总行数,证明换行符确实被完整保留了。
3. 将结果存入数组后遍历
CLOUDS=($(jq -r '.clouds[].cloud_name' publicClouds.json)) for CLOUD in $CLOUDS do echo "> $CLOUD" done
这种写法能正常逐个输出云名称,本质是用数组单独存储了每个名称。CLOUDS=($(jq ...))会先把命令输出拆成片段,再把每个片段单独放进数组的一个位置——数组第1个元素对应第一个云名称,第2个元素对应第二个,以此类推。遍历的时候,$CLOUDS会展开数组所有元素,for循环就挨个处理。更稳妥的写法是for CLOUD in "${CLOUDS[@]}",这样就算云名称里有空格,也不会被错误拆分。
内容的提问来源于stack exchange,提问作者Brendan Stephens
相关产品推荐
相关产品推荐

