for i in $(xrandr); do echo "$i" ; donefor i in "$(xrandr)"; do echo "$i"; donefor i in "$(xrandr)"; do echo $i; done
我理解为什么1与2不同。但是为什么3与2给出不同的输出?请也解释输出。报价如何在换行符上工作?
for i in $(xrandr); do echo "$i" ; donefor i in "$(xrandr)"; do echo "$i"; donefor i in "$(xrandr)"; do echo $i; done我理解为什么1与2不同。但是为什么3与2给出不同的输出?请也解释输出。报价如何在换行符上工作?
Answers:
在类似Bourne的shell中,未加引号的变量(如$var)或命令替换(如$(cmd)或`cmd`)是split + glob运算符。
也就是说,它们的内容根据$IFS特殊变量的当前值(默认情况下包含空格,制表符和换行符)进行拆分
然后,由该拆分产生的每个单词都将受文件名生成(也称为globbing或文件名扩展)的影响,也就是说,它们被视为模式,并被扩展到与该模式匹配的文件列表。
因此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在for循环的一部分中仅使用split + glob运算符(仅保留命令替换或变量扩展未引用):
set -f; unset -v IFS
for i in $(xrandr); do whatever with "$i"; done
如果要循环输出的(非空)行,则xrandr需要设置$IFS为换行符:
IFS='
'
带引号的换行符是换行符。因此echo "$1"给echo一个命令行参数,然后直接打印换行符。
未引用的换行符是空格。因此,echo $1给了许多命令行参数以回显,这将它们一个接一个地打印出来,并用空格隔开。