我应该在终端中使用“set -u”吗?为什么它会破坏 git 的自动完成功能?

我应该在终端中使用“set -u”吗?为什么它会破坏 git 的自动完成功能?

我添加了set -u(相当于set -o nounset.bashrc,但现在一些选项卡自动完成失败,并出现有关未设置变量的错误。一个例子是git自动完成。

这是否是一个自动完成错误,或者在交互式终端中git使用通常是一个坏主意?set -u有没有其他方法可以在不破坏自动完成功能的情况下保护自己?

(我在 Windows/cygwin 和 RHEL 上使用“git bash”时遇到同样的问题。)

答案1

set -u来自 Bourne shell 或更明确的set -o nounset来自 Korn shell(两者都是 POSIX)更多的是一种编程工具,用于检测代码中的拼写错误或初始化变量的使用。

这是编程风格的选择。一旦设置,您就不能让代码取消引用未设置的变量,这意味着您必须以不同的方式编写代码。

例如,您不能:

if [ -n "$TERM" ]; then
  echo running in a terminal
fi

您需要解决nounsetwith${TERM-}代替$TERM或 use 的问题[[ -v TERM ]]

有些与大多数其他选项一起使用,例如errexitorfailglob或 ,pipefail它们改变了 shell 的工作方式,并且代码编写者需要调整他们的代码。

现在,在交互式 shell 中,如果您不使用其他人编写的代码,那么这不会成为问题。

问题是 bash 没有相当于 zsh 的emulate -L功能,第三方函数可以为自己的代码显式请求本地合理的选项基线。

在 zsh 中,完成代码通常执行以下操作:

some-completion-function() {
  emulate -L zsh # default set of options in the zsh emulation set locally
  set -o extendedglob -o errreturn # additional local options as needed

  code here not impacted by the users options
}

bash 中没有等效项,虽然最近版本的bashhas local -(来自 ash)可以为 所设置的选项设置本地范围set,但 . 所设置的选项没有等效项shopt。由于没有等效的emulate,您需要将所有选项硬编码为其默认值,其列表随 bash 版本而变化。

值得一提的是,bash_completion(这是一个独立于 bash 本身的独立项目)全局更改默认选项(不仅是其自身),并且希望您不要更改它。例如,它设置extglobprogcomp

您会发现它有时会临时设置选项,例如verbosenoglob或者nullglob通过将旧设置保存在变量中并随后恢复来笨拙地设置选项。

在 bash 和 zsh 中,甚至有一些选项会影响代码的解析方式,因此应在加载完成代码(或任何第三方代码)后设置这些选项。在zsh中,大部分补全代码是自动加载第一次使用时,自动加载可以独立于用户的选项或别名(-z以及-U的选项autoload)来完成,但同样在 bash 中没有等效项。

因此,您会发现有很多选项一旦更改了默认值,就会导致 bash 完成失败(noglobnounseterrexiterrreturnfailglob可能还有更多)。更改$IFSIIRC 值也会导致问题(或至少习惯于)。虽然其中一些可能被认为是 bash_completion 的错误,但在大多数情况下,你不能真正责怪它们,因为问题是 bash 没有工具来应对不同选项集的要求。

因此,如果您要更改选项,请做好在 shell 中使用的某些第三方代码失败的准备。

相关内容