如何为循环下标返回空白项目

时间:2013-10-20 14:53:54

标签: bash

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

这可以打印两行:

  

a b

     

c d

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

这将打印四行:

'a
b'
'c
d'

我尝试将数组与eval一起使用。这有效。

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

这项工作做得很好并打印出两行:

  

a b

     

c d

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

我希望在$(echo“'a b''c d'”)中迭代i,就像我在'a b''c d'

中的i一样

2 个答案:

答案 0 :(得分: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 builtin命令将行拆分为单词。默认值为``&lt; space&gt;&lt; tab&gt;&lt; newline&gt;''。

  • 还要注意分配&lt; newline&gt;的有点复杂的方式到IFS:IFS=$'\n'

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

第二个解决方案:

  • 我们使用eval array=($(echo "'a b' 'c d'"))而不是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):

      

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

         

    @从1开始扩展到位置参数。当扩展发生在双引号内时,每个参数都会扩展为单独的单词。也就是说,“$ @”相当于“$ 1”“$ 2”...如果双引号扩展发生在一个单词中,则第一个参数的扩展与原始单词的开头部分连接,并且扩展最后一个参数与原始单词的最后一部分连接在一起。当没有位置参数时,“$ @”和$ @展开为空(即,它们被删除)。

答案 1 :(得分:0)

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

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