我们建议,在 bash 脚本中,我们不应该解析 ls 的输出
上面链接的网页推荐如下代码:
# Good!
for f in *; do
[[ -e $f ]] || continue
...
done
或用文件名填充数组
myfiles=( ~/* )
但是,当我查看这些示例,并了解 bourne shell 一般如何处理不带引号的字符串时,我的感觉是,如果我在包含空格的文件名上使用此代码,则 glob 将爆炸文件上的每个(空格分隔的)单词。例如如果我有以下目录
$ ls -1
a file I downloaded from the net.pdf
apple.sh
hello world.txt
我运行这个
for file in *
do printf "%s\n" "$file"
done
我期待未加引号的字符串行为。例如
a
file
I
downloaded
from
the
net.pdf
apple
hello
world
但我得到的是正确的行为
a file I downloaded from the net.pdf
apple
hello world
与数组类似
myfiles=( * )
declare -p myfiles
declare -a myfiles='([0]="a file I downloaded from the net.pdf" [1]="apple" [2]="hello world")'
我的问题是这是为什么?
是因为分词后进行了全局扩展吗? (以便这些类型的文件操作产生正确的输出?)
答案1
文件名扩展发生在分词之后
https://www.gnu.org/software/bash/manual/html_node/Shell-Expansions.html#Shell-Expansions
展开的顺序是:大括号展开;波形符扩展、参数和变量扩展、算术扩展和命令替换(以从左到右的方式完成);分词;和文件名扩展。
答案2
[[ -e $f ]]
是一个特例。[[
是保留字;之间[[
和]]
不同的规则都有效。其中之一是不执行分词。