for i in $(xrandr); do echo "$i" ; done
for i in "$(xrandr)"; do echo "$i"; done
for i in "$(xrandr)"; do echo $i; done
我理解为什么1与2不同。但是为什么3与2给出不同的输出?请也解释输出。报价如何在换行符上工作?
for i in $(xrandr); do echo "$i" ; done
for i in "$(xrandr)"; do echo "$i"; done
for 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
给了许多命令行参数以回显,这将它们一个接一个地打印出来,并用空格隔开。