带引号与不带引号的字符串扩展

带引号与不带引号的字符串扩展
  1. for i in $(xrandr); do echo "$i" ; done
  2. for i in "$(xrandr)"; do echo "$i"; done
  3. for i in "$(xrandr)"; do echo $i; done

我明白为什么 1 与 2 不同。但是为什么 3 给出的输出与 2 不同?请也解释一下输出。换行符上的引号如何工作?

答案1

不带引号的变量(如$var)或命令替换(如$(cmd)`cmd`)是分割+全局类似 Bourne shell 的操作符。

也就是说,它们的内容根据$IFS特殊变量的当前值进行分割(默认情况下包含空格、制表符和换行符)

然后分裂产生的每个单词都会受到文件名生成(也称为通配或者文件名扩展),也就是说,它们被视为模式并扩展到与该模式匹配的文件列表。

因此for i in $(xrandr),在 中$(xrandr),由于 不在引号内,因此按空格、制表符和换行符序列进行分割。并且检查该分割产生的每个单词是否匹配文件名(或者如果它们不匹配任何文件则保持原样),并for循环遍历它们。

在 中for i in "$(xrandr)",我们没有使用 split+glob 运算符作为命令替换被引用,所以循环中有一次xrandr值:(不带尾随换行符的输出命令替换带子)。

然而,在echo $i,中$i再次未被引用,因此 的内容再次$i被分割并受文件名生成这些作为单独的参数传递给echo命令(并echo输出用空格分隔的参数)。

所以吸取的教训是:

  • 如果你不想分词或者文件名生成,始终引用变量扩展和命令替换
  • 如果你确实想要分词或者文件名生成,将它们不加引号,但进行$IFS相应设置和/或启用或禁用文件名生成(如果需要)(set -f, set +f)。

通常,在上面的示例中,如果您想循环 的输出中空白分隔的单词列表xrandr,您需要:

  • 保留$IFS默认值(或取消设置)以在空白处拆分
  • 用于set -f禁用文件名生成,除非您确定xrandr永远不会输出任何*?[字符(这是文件名生成模式中使用的通配符)

in然后在循环部分仅使用 split+glob 运算符(仅保留命令替换或变量扩展不带引号)for

set -f; unset -v IFS
for i in $(xrandr); do whatever with "$i"; done

如果你想循环(非空)线对于xrandr输出,您需要设置$IFS为换行符:

IFS='
'

答案2

引用的换行符是换行符。因此,echo "$1"为 echo 提供一个命令行参数,然后直接打印换行符。

不带引号的换行符是空格。因此,echo $1给 echo 提供了许多命令行参数,它会依次打印它们,并用空格分隔。

相关内容