当尝试获取文件时,您是否不希望出现一个错误,提示该文件不存在,以便您知道要修复什么?
例如,非易失性建议将其添加到您的配置文件/rc 中:
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm
如上所述,如果nvm.sh
不存在,您将收到“无提示错误”。但如果你尝试. "$NVM_DIR/nvm.sh"
,输出将会是FILE_PATH: No such file or directory
。
答案1
在 POSIX shell 中,.
是一个特殊的内置命令,因此它的失败会导致 shell 退出(在某些 shell 中,例如bash
,它仅在 POSIX 模式下完成)。
什么是错误取决于 shell。并非所有这些都在解析文件时因语法错误而退出,但大多数会在无法找到或打开源文件时退出。我不知道如果源文件中的最后一个命令返回非零退出状态(当然,除非该errexit
选项打开),任何命令都会退出。
在这里做:
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
在这种情况下,如果文件存在,您希望获取该文件的源,如果文件不存在(或者此处为空-s
),则不获取该文件的源。
也就是说,如果该文件不存在,则不应将其视为错误(POSIX shell 中的致命错误),该文件被视为可选文件。
如果文件不可读或者是一个目录,或者(在某些 shell 中)如果在解析文件时出现语法错误,这仍然是一个(致命)错误,这将是应该报告的真正错误情况。
有些人会认为存在竞争条件。但它唯一意味着,如果在 和 之间删除文件,shell 将退出并出现错误[
,.
但我认为,在脚本执行时,此固定路径文件会突然消失,认为这是一个错误是有效的。跑步。
另一方面,
command . "$NVM_DIR/nvm.sh" 2> /dev/null
其中command
¹ 删除了特别的命令的属性.
(因此它不会在错误时退出 shell)将不起作用:
- 它会隐藏
.
的错误,还会隐藏源文件中运行的命令的错误 - 它还会隐藏真正的错误情况,例如文件具有错误的权限。
其他常见语法(例如,参见grep -r /etc/default /etc/init*
Debian 系统上尚未转换的初始化脚本systemd
(其中EnvironmentFile=-/etc/default/service
用于指定可选环境文件))包括:
[ -e "$file" ] && . "$file"
检查文件是否存在,如果它是空的,仍然获取它。如果无法打开它仍然是致命错误(即使它在那里,或者曾经在那里)。您可能会看到更多变体,例如
[ -f "$file" ]
(exists and is a常规的文件)、[ -r "$file" ]
(可读)或这些的组合。[ ! -e "$file" ] || . "$file"
稍微好一点的版本。更清楚地表明文件不存在是正常情况。这也意味着
$?
将反映最后运行的命令的退出状态$file
(在前面的情况下,如果您得到1
,您不知道它是因为$file
不存在还是该命令失败)。command . "$file"
期望该文件存在,但如果无法解释则不要退出。
[ ! -e "$file" ] || command . "$file"
上述的组合:如果文件不存在也没关系,对于 POSIX shell,会报告打开(或解析)文件的失败,但不是致命的(这可能更适合
~/.profile
)。
1 注意:但是,除非在仿真中,否则zsh
不能command
这样使用;sh
请注意,在 Korn shell 中,source
实际上是 的别名command .
,是 的非特殊变体.
答案2
维护者的nvm
回应:
只需删除文件即可轻松卸载nvm;强制进行额外的工作(追踪源 nvm 的行)似乎并不特别有价值。
我的解释(结合Stéphane的出色解释和Kusalananda的评论):
它更简单、更安全。
它可以防止 POSIX shell 在启动时由于丢失文件(由于各种原因)而退出。使用非 POSIX(例如 bash)shell 的用户可以根据需要删除条件。
答案3
作为杰巴林和斯蒂芬·查泽拉斯已经指出,在 POSIX shell 中,获取不存在的文件会导致登录失败。
但是添加测试来查看文件是否存在,然后尝试获取它可能会导致称为竞争条件的情况。如果和nvm.sh
之间发生了一些变化,它就会导致他们试图阻止的错误,尽管这种情况很少见。[ -s nvm.sh ]
. nvm.sh
一般来说,防止竞争条件的方法是只尝试你想做的事情,然后在失败时处理错误,例如
. "$NVM_DIR/nvm.sh" || echo "Sourcing $NVM_DIR/nvm.sh failed" >&2
事实证明,这在 POSIX shell 中不起作用,因为如上所述,.
失败将导致 shell 在任何错误处理运行之前立即退出。
我的回答认为 POSIX shell 与这个问题无关,因为.bash_profile
不应该在 POSIX 模式下运行。所以我们无论如何都可以执行上面的代码。
为了最安全,我们可以确保 POSIX 模式不起作用,或者使用中描述的技术确保禁用 POSIX 模式https://unix.stackexchange.com/a/383581/3169。
Stéphane 的答案对如何处理所有 POSIX shell 提供了一些有用的建议,我认为这是 nvm 作者的意图,但与这里提出的问题略有不同,这就是为什么我们有多种可能的方法,具体取决于您的目标是什么。