为什么我无法在 bash 脚本中转义空格?

为什么我无法在 bash 脚本中转义空格?

我试图在 Bash 中转义路径的空格字符,但都没有使用反斜杠或者引号作品。

.sh脚本:

ROOT="/home/hogar/Documents/files/"
FILE=${ROOT}"bdd.encrypted"
DESTINATION="/home/hogar/Ubuntu\ One/folder"

mv ${FILE} ${DESTINATION}

执行脚本 ( ./file) 后,结果如下:

mv: target 'One/folder' is not a directory

为什么mv命令会分割字符串,如何阻止这种情况发生?

答案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将看到-xas $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}"

相关内容