为什么 mkdir 在带有 BIN_DIR="~/bin/" 的脚本中失败(没有这样的文件或目录)?

Hen*_*dré 10 command-line bash scripts home-directory mkdir

为什么 mkdir 命令失败并显示:“没有这样的文件或目录”?

#!/bin/bash

set -e

BIN_DIR="~/bin/"

if [ ! -d "$BIN_DIR" ]; then
  mkdir "$BIN_DIR"
fi
Run Code Online (Sandbox Code Playgroud)

Zan*_*nna 23

它不起作用,因为~被引用。双引号 "抑制波浪号扩展。没有具有字面名称的目录~/bin。如man bash(强调我的)中所述:

波浪号扩展

如果单词以未加引号的波浪号字符 (`~')开头,则第一个未加引号的斜杠之前的所有字符(或所有字符,如果没有未加引号的斜杠)都被视为波浪号前缀。如果没有引用波浪号前缀中的任何字符,则波浪号后面的波浪号前缀中的字符将被视为可能的登录名。如果此登录名是空字符串,则代字号将替换为 shell 参数 HOME 的值。如果未设置 HOME,则会替换执行 shell 的用户的主目录。否则,波浪号前缀将替换为与指定登录名关联的主目录。

您可以删除引号,因为它~是路径中~/bin唯一会导致 shell 执行扩展的字符,在这种情况下我们需要扩展。shell不会对波浪号扩展的结果执行任何进一步扩展,至少在 Bash 4 中,所有当前或远程最近版本的 Ubuntu都具有. 因此,即使您的主目录包含不寻常的字符(如空格),也没关系。

或者你可以使用$HOME代替~,因为参数扩展不是由双引号抑制,只有单引号。双引号确实确保扩展值本身不受任何进一步扩展的影响,因此不会发生分词文件名扩展。因此,$HOME即使使用奇怪命名的主目录,只要保留双引号,也可以使用。

  • @pa4080 `~` 的扩展不是参数扩展的一部分。 (2认同)

pa4*_*080 11

产生错误消息是因为~引用了波浪号,如 Zanna's answer 中所述。如果要使用~,脚本的相关部分应该是:

BIN_DIR=~/bin/
Run Code Online (Sandbox Code Playgroud)

如果出于某种原因要引用字符串,则可以使用环境变量$HOME

BIN_DIR="$HOME/bin/"
Run Code Online (Sandbox Code Playgroud)

在我看来,第二种方法是更好的做法。

  • 在脚本中使用 `~` 没有错。它的工作方式与命令行完全相同。问题是引用会阻止波浪号扩展,如 [Zanna 的回答](https://askubuntu.com/a/977359/85695) 中所述。 (6认同)
  • 但是这里的命令行和脚本之间绝对没有区别。这是在脚本中的事实完全无关紧要,您将在命令行中遇到完全相同的错误。问题是引用,而不是它在脚本中。 (5认同)
  • @pa4080 你能解释一下*为什么*你认为扩展`$HOME`比使用波浪号扩展更好吗?你给出的唯一解释是,“这是一个更好的主意,因为你应该少注意。” 我不知道这意味着什么。你能在编辑中详细说明吗?没有它,就没有任何东西支持你的答案,所以它肯定属于它。POSIX 需要波浪号扩展 [现在已经有一段时间了](http://pubs.opengroup.org/onlinepubs/7908799/xcu/chap2.html#tag_001_006) *并且*脚本的 hashbang 行是 `#!/bin /bash` 所以我认为可移植性不是原因。 (3认同)