我有以下Bash脚本:
DIR="~/Folder/With\ Spaces"
CMD="find $DIR -type f"
# echo showing hidden characters
echo $CMD | cat -v
while read line
do
echo $line
done < <($CMD)
输出:
find ~/Folder/With\ Spaces -type f
find: ~/Folder/With\: No such file or directory
find: Spaces: No such file or directory
我已经通过我能想到的每一种方式,单引号和双引号,反斜杠和没有反斜杠,在其他行中的变量引用,没有骰子。
如果我理解正确,CMD应该如下:
find ~/Folder/With\ Spaces -type f
这应该可以正常工作,并且由于find
不能在其路径周围使用引号,因此这是正确的方法。回声显示它与此匹配。在命令行中键入此字符串可以正常工作。同样,echo
命令打印出来。但是脚本的输出表明还有其他事情发生,可能是在执行命令的done
行。
如何让Bash将文件名解释为此上下文中的一个路径?为什么?反斜杠(以阻止它将它解释为由空格分隔的两个部分)被视为字符串的一部分,那么它在哪里拆分,为什么?
答案 0 :(得分:5)
Bash永远不会将数据作为代码进行评估,但它会做一些可以让你认为它做的事情(即分词和通配)。由于\
是shell语法的一部分,因此在展开变量时不会将其重新解释为转义序列。
这是你应该怎么做的:
DIR=~/"Folder/With Spaces" # ~ doesn't expand in quotes, and there's no "\".
CMD=(find "$DIR" -type f) # use an array to keep track of words
# Print the words escaped so you know what will actually be executed
printf "%q " "${CMD[@]}" | cat -v
echo
while IFS= read -r line # don't split or interpret words
do
echo "$line" # use quotes to prevent globbing and word splitting
done < <("${CMD[@]}") # run the command in the array without spacing issues