fer*_*raz 8 shell zsh function
我刚刚决定尝试 zsh(通过 oh-my-zsh),现在我正在precmd尝试模拟一个两行提示,该提示不仅仅在最后一行中有正确的提示。
所以我克隆了默认主题,并受到这篇文章的启发(我也用它来学习很多东西),我做这样的事情(我稍后会添加颜色):
function precmd {
local cwd="${(%):-[%~]}"
local who_where="${(%):-%n@%m}"
local git_info=${(%)$(git_prompt_info)}
local right_prompt=" $git_info [$who_where]"
local left_prompt="${(r:(($COLUMNS - ${#${right_prompt}})):: :)cwd}"
echo "$left_prompt$right_prompt"
}
Run Code Online (Sandbox Code Playgroud)
它有效。但我不禁想知道:每次调用 precmd 时,zsh 是否都定义了所有这些变量?
我一直在搜索与 zsh 相关的闭包、范围和命名空间,希望将本地变量作为数据附加到 precmd,因此不需要每次都重新定义变量,但我什么也没找到。有什么方法可以做我正在尝试的事情,还是应该放弃它?
作为旁注,并且仅当它相关时,“加载函数”是什么意思?
Mat*_*att 11
Zsh 没有闭包、包或命名空间之类的东西。Zsh 缺少一些真正闭包所需的东西:
函数不是一流的。您不能将函数作为参数传递给其他函数,并且函数不能返回其他函数。(您可以传递要调用的函数的名称,但这与传递函数本身不同)。
你不能有嵌套函数。zsh 中的所有函数都是全局的。您必须为函数名称添加前缀以避免冲突。请特别注意,函数会隐藏同名的外部程序。如果您有一个ls被调用的函数,它将被调用而不是程序ls。这可能很有用,除非您不小心这样做。
变量是动态范围的,而不是像大多数现代语言那样静态范围。即使您可以使用嵌套函数,内部函数也不会以您通常期望的方式关闭外部函数的局部变量。你不能用它们来制作模块,就像人们在 JavaScript 中所做的那样。
Zsh确实有匿名函数,但如果没有这些其他东西,它们就没有多大用处。
所以基本上,你能做的最好的事情就是为你的所有函数和全局变量加上前缀。
我还要指出,你应该precmd像这样定义你的:
% autoload -Uz add-zsh-hook
% add-zsh-hook precmd my_precmd_function
Run Code Online (Sandbox Code Playgroud)
add-zsh-hook允许您将函数挂钩,precmd而不会覆盖任何其他可能也想挂钩的函数precmd。
加载函数意味着什么是一个单独的问题。Zsh 具有自动加载功能,仅在实际调用时才从磁盘加载函数。当您这样做时autoload -Uz foobar,这将使名为的函数foobar可供调用。当您实际调用 时foobar,它会从磁盘加载定义。
不,闭包对于 zsh 来说太复杂了。Zsh 旨在解释与直接交互相距不远的小脚本。它没有花哨的语言功能,这些功能对于大型编程非常有用,但对于通常使用 shell 的那种小任务则不太有用。
请注意,如果存在某种形式的闭包,允许一次性预先计算变量的值然后存储,则当某些更改导致信息无效时,这些值将不会更新。
$git_info由于对签入 git 或 git 存储库的文件的修改,派生变量可以随时更改。因此,无论如何,每次都需要重新计算它们。
您可以将cwd和的值缓存who_where在全局变量中,因为它们在正常操作下不会更改。cwd当当前目录更改时更改,因此需要从chpwd. 然而,这些变量的计算速度非常快,所以没有必要费心。这里昂贵的计算正在运行git_prompt_info,并且可以随时更改。
当您在每个命令之间显示信息时,最好将其作为提示(PS1或psvar数组)的一部分。Zsh 知道它必须在各种情况下重新显示提示,而它对您从precmd.