为何在命令中直接使用数组会取消输出重定向?
问题描述
我有两段简化后的Shell代码:
第一段代码能按预期将输出重定向到$log_file:
elems="${array[@]}" do_cmd "xxx" "for_each \"$elems\" func" ">> $log_file" || return $?
但将代码简化为第二段后,输出不再重定向到$log_file,而是直接输出到stdout:
do_cmd "xxx" "for_each \"${array[@]}\" func" ">> $log_file" || return $?
补充说明:do_cmd内部使用eval执行传入的参数,for_each函数定义如下:
for_each() { local elems=$1 local func_and_args=$2 for elem in $elems do $func_and_args $elem done }
原因分析
核心问题出在**${array[@]}在双引号中的展开特性**,以及Shell参数传递的规则:
第一段代码的执行逻辑
elems="${array[@]}"会把数组所有元素拼接成一个完整字符串(元素间用默认空格分隔)。- 传给
do_cmd的第二个参数是完整的"for_each \"$elems\" func",整个for_each调用是一个独立参数。 do_cmd通过eval拼接执行时,命令结构为xxx for_each "a b c" func >> $log_file(假设数组元素为a、b、c),重定向符号被正确识别为整个命令的输出重定向,因此生效。
第二段代码的执行逻辑
- 双引号内的
${array[@]}会将数组每个元素拆成单独参数项。比如数组元素是a和b,"for_each \"${array[@]}\" func"会被拆成for_each "a"和b" func"两个独立参数。 - 这打乱了
do_cmd的参数列表,原本的>> $log_file变成了更靠后的参数,不再属于for_each调用的输出重定向部分。 eval执行时无法正确解析重定向规则,导致输出直接流向默认的stdout。
- 双引号内的
同时,这种写法还会让for_each的第一个参数只能拿到数组的第一个元素,循环无法遍历所有元素,但这是次要问题,重定向失效的核心是参数被错误拆分。
内容的提问来源于stack exchange,提问作者pmor
相关产品推荐
相关产品推荐

