为什么“对于“ $ list”中的项目”仅重复一次?

时间:2018-08-22 15:45:10

标签: shell loops posix

我有这个简单的代码:

#~/bin/sh

partitions="$(ls -1 /dev/loop?* | tr '\n' ' ')"
for partition in ${partitions}
do
  echo "A loop partition: ${partition}"
done

有输出

A loop partition: /dev/loop0
A loop partition: /dev/loop1
A loop partition: /dev/loop2
A loop partition: /dev/loop3
A loop partition: /dev/loop4
A loop partition: /dev/loop5
A loop partition: /dev/loop6
A loop partition: /dev/loop7
A loop partition: /dev/loop-control

当我在${partitions}循环中的for变量周围加上引号(使其变为"${partitions}")时,输出将变得不同。

带引号:

#~/bin/sh

partitions="$(ls -1 /dev/loop?* | tr '\n' ' ')"
for partition in "${partitions}"
do
  echo "A loop partition: ${partition}"
done

新输出:

A loop partition: /dev/loop0 /dev/loop1 /dev/loop2 /dev/loop3 /dev/loop4 /dev/loop5 /dev/loop6 /dev/loop7 /dev/loop-control 

为什么报价会以这种方式影响输出?

有人告诉我,将${vars}放在shell脚本的引号中是一种好习惯。这实际上是不好的做法吗?

2 个答案:

答案 0 :(得分:3)

使用引号可防止字符串拆分(将其中包含单词的项目分解为多个片段)和全局扩展(将每个片段视为可能与多个文件名匹配的模式)。

但是,您的原始代码依赖于字符串拆分,因为它会将partitions存储为单个字符串。请勿这样做:将列表存储在数组变量中,这样即使抑制了字符串拆分也可以保留单独的标识。

shopt -s nullglob                  # cause a glob with no matches to not generate any items
partitions=( /dev/loop?* )         # generate our list of partitions *as an array*
for partition in "${partitions[@]}"; do       # ...then iterate over "${array[@]}"
  echo "A loop partition: ${partition}"
done

上面的方法更有效(它仅使用内置在shell本身中的工具,而ls不是),并且更正确(它不会将文件名用空格分割成单独的单词,也不会替换在存在此类名称时,请使用其他文件名)。

答案 1 :(得分:2)

在变量周围加上引号会使它的值变成单个单词,即使它包含空格也是如此。但是,for遍历变量中的单词。您已经明确创建了一个变量,并用空格将其分隔开来,然后通过添加引号来关闭单词拆分。