1
for i in 'a b' 'c d'; do echo $i;done

这可以打印两行:

抗体

光盘

for i in $(echo "'a b' 'c d'");do echo $i;done

这将打印四行:

'a
b'
'c
d'

我尝试将数组与eval.This一起使用

eval array=($(echo "'a b' 'c d'")
for ((i=0;i<${#array[@]};i++));do echo ${array[$i]};done

这很好用并打印两行:

抗体

光盘

还有另一种简单的方法吗?

我希望迭代 for i in $(echo "'a b' 'c d'") 就像 for i in 'a b' 'c d'

4

2 回答 2

2

我假设您有一些被构造为空格分隔列表的变量,并且您的项目可能包含空格。

如您所见,这在 bash 中迭代很尴尬。

如果您对变量生成有任何控制权,请考虑将其设置为:

lines="a b
c d"
( IFS=$'\n' ; for i in $lines ; do echo $i ; done ; )

如果您无法控制变量的创建,您仍然可以使其不那么复杂:

eval array=($(echo "'a b' 'c d'"))
for i in "${array[@]}" ; do echo $i ; done

更新——如下所述,一些解释是有序的:

第一种解决方案:

  • 来自 man bash:

    IFS
    内部字段分隔符,用于扩展后的分词,并使用 read 内置命令将行拆分为单词。默认值为 ``<space><tab><newline>''。

  • 还要注意将 <newline> 分配给 IFS 的有点复杂的方式:IFS=$'\n'

  • 这里我们使用(...)将 IFS 的范围封装在一个子 shell 中。如果您不关心 IFS 的值会被更改,或者如果您设计了另一种方法来恢复它的原始值,则可以不使用它,例如saved_ifs=$IFS ; ... ; IFS=$saved_ifs

第二种解决方案:

  • 我们使用eval array=($(echo "'a b' 'c d'"))and not array=('a b' 'c d'),因为当我们有myvar="'a b' 'c d'"(或我尝试过的任何其他组合)array=($myvar)时不会做正确的事情(带或不带引号),但eval array=($(echo $myvar))会被评估为array=('a b' 'c d').

  • "${array[@]}"注意和之间的区别"${array[*]}";它类似于 "$@" 和 "$*" 之间的区别(同样来自 man bash):

    * 扩展到位置参数,从一开始。当扩展出现在双引号内时,它会扩展为一个单词,每个参数的值由 IFS 特殊变量的第一个字符分隔。也就是说,“$*”等价于“$1c$2c...”,其中c是IFS变量值的第一个字符。如果未设置 IFS,则参数以空格分隔。如果 IFS 为空,则将参数连接起来而不插入分隔符。

    @ 展开为位置参数,从一开始。当扩展出现在双引号内时,每个参数都扩展为一个单独的单词。即 "$@" 等价于 "$1" "$2" ... 如果双引号展开出现在一个单词中,则第一个参数的展开与原词的开头部分连接,展开的最后一个参数与原始单词的最后一部分连接。当没有位置参数时,"$@" 和 $@ 扩展为空(即,它们被删除)。

于 2013-10-20T16:03:56.980 回答
0

目前尚不清楚为什么你认为你需要eval这里。以下将做同样的事情:

array=('a b' 'c d')
for line in "${array[@]}"; do
    echo "$line"
done
于 2013-10-21T12:43:41.523 回答