![为什么我无法在 bash 脚本中转义空格?](https://linux22.com/image/157673/%E4%B8%BA%E4%BB%80%E4%B9%88%E6%88%91%E6%97%A0%E6%B3%95%E5%9C%A8%20bash%20%E8%84%9A%E6%9C%AC%E4%B8%AD%E8%BD%AC%E4%B9%89%E7%A9%BA%E6%A0%BC%EF%BC%9F%20.png)
答案1
您正在扩展 DESTINATION 变量,如果您echo
这样做,您将得到:
echo ${DESTINATION}
/home/hogar/Ubuntu\ One/folder
但mv
不明白这一点:
mv ${FILE} ${DESTINATION}
mv: cannot move '/home/hogar/Documents/files/bdd.encrypted' to '/home/hogar/Ubuntu\\ One/folder': No such file or directory
(由于某种原因,我的MV更加冗长)
为了防止这种情况,您应该使用引号:
mv "${FILE}" "${DESTINATION}"
如果您不需要扩展(因为您之前已经在扩展),则只需使用"$..."
就足够了:
mv "$FILE" "$DESTINATION"
答案2
您准备变量的步骤“足够接近”并且可以工作,但它确实显示出理解上的弱点(这就是您发布的原因!)
对 DESTINATION 的分配只需是以下两者之一:
DESTINATION="/home/hogar/Ubuntu One/folder"
或者
DESTINATION=/home/hogar/Ubuntu\ One/folder
双引号打开引用(一种具有一定魔力的形式),反斜杠能够引用其后的单个字符。我个人认为使用双引号的形式更好,因为视觉上它更好。
顺便说一句,出于类似的原因,我会执行 FILE 分配,例如:
FILE="${ROOT}bdd.encrypted"
${NAME}
这显示了相当罕见的情况,而不是简单地使用$NAME
- 将变量名称与后面的任何字母分开。事实上,如果 ROOT 的定义上没有尾随 /,我会写成
FILE="$ROOT/bdd.encrypted"
看起来更好。它也会偶尔给你带来一些我不会提及的好处;根据我的经验,尾部斜线往往更不受欢迎,而不是受欢迎,而且绝对不需要它们。 (当涉及到符号链接时,它确实会产生影响,但这对于这个已经很大的答案来说绝对是太多细节了)。
你的问题的关键实际上发生在MV命令,应写为
mv "$FILE" "$DESTINATION"
因为现在,你永远不知道什么时候表示路径的变量中会有空格。再次注意避免使用括号来进行简单的变量扩展。
您遇到问题的原因是 shell 用来构建命令行的过程。如果你仔细阅读 shell 手册,它基本上说变量(和其他一些东西)被扩展然后它会寻找空格。当然,这个过程会更加复杂,但这就是您的问题的要点。
还有一点相关且值得了解:$*
、$@
和"$*"
之间的区别"$@"
。那我就来说说吧!
如果您有一个 shell 脚本,可以这样调用:
foo -x "attached is the software" "please read the accompanying manual"
然后foo
将看到-x
as $1
,以及两个字符串 as$2
和$3
(出于显而易见的原因,您应该将其访问为"$2"
和"$3"
)。但是,如果您想将整组参数传递给另一个脚本,则以下脚本将在所有空间上遭受可怕的分裂:
bar $*
以下内容(这是原始 Bourn shell 0.X 版本中的唯一方法)将导致所有参数作为单个字符串传递(也是错误的)
bar "$*"
因此添加了以下语法作为一个非常特殊的神奇情况:
bar "$@"
它故意将 的各个成员引用为$*
完整的引用字符串,但将它们分开。现在每个人都是赢家。
尝试$@
不使用时的其他效果有点有趣"$@"
,但你很快就会发现它实际上并没有那么有趣......它只是解决主要问题的特殊情况。
所有支持数组的现代 shell 在特殊情况下也使用 @:
${arr[*]}
"${arr[*]}"
"${arr[@]}"
其中第一个将在所有空格上分裂,导致不可预测数量的单独单词,第二个将在一个字符串中产生所有数组成员,第三个将很好地为每个数组成员提供作为单独的完整引用字符串。
享受!
答案3
是的,当您将值分配给 时,您转义了空格$DESTINATION
,
但是当你用 mv 命令使用它时,你没有
mv ${FILE} ${DESTINATION}
使用这个代替:
mv "${FILE}" "${DESTINATION}"