在fish shell中定义别名

286

我想在fish shell中定义一些别名。显然可以在

~/.config/fish/functions

但是当我重新启动shell时,它们没有自动加载。有什么想法吗?


1
下面只有几个投票的答案,在我看来是正确的。只有一个函数每个文件时,只有在./config/fish/functions中的自动加载才有效。 - mc_electron
12个回答

495

只需使用alias,以下是基本示例:

# Define alias in shell
alias rmi "rm -i"

# Define alias in config file ( `~/.config/fish/config.fish` )
alias rmi="rm -i"

# This is equivalent to entering the following function:
function rmi
    rm -i $argv
end

# Then, to save it across terminal sessions:
funcsave rmi

最后这个命令创建了文件~/.config/fish/functions/rmi.fish

有兴趣的人可以在官方手册中了解更多关于 fish 别名的内容。


4
请注意,在fish shell中,别名只是一个包装函数的shell脚本。 - user456584
39
这只是一个需要放置在哪个文件中的说明。我把我的放在 ~/.config/fish/config.fish 中,这样每次我运行终端时都会加载它。 - Ira Herman
我们难道不需要像在bash中使用"$@"一样引用"$argv"来处理带有空格的参数吗? - kyb
@kyb,不是的,Fish比Bash更聪明。实际上,Fish中的所有变量都是数组。请前往Shell variables并向下滚动到数组子部分。 - glenn jackman
在交互式fish会话中尝试以下内容:set v foo bar "baz quz"; printf '%s\n' $v; printf '%s\n' "$v",并尝试使用set命令的--show选项进行实验。 - glenn jackman
显示剩余3条评论

129

这是我如何定义一个新的函数 foo,运行它并将其持久化保存。

sthorne@pearl~> function foo
                    echo 'foo was here'
                end
sthorne@pearl~> foo
foo was here
sthorne@pearl~> funcsave foo

谢谢Jerub。不知何故,在funcsave之后它给了我一个错误: troff:致命错误:无法打开“/usr/share/fish/man/save_function.1”:没有那个文件或目录。 - armandino
9
你可以使用 funced 命令编辑函数。例如,funced foo 可以编辑名为 foo 的函数。 - Dennis
15
运行 funcsave {some_function_name} 将会把函数保存在 ~/.config/fish/functions/{some_function_name}.fish - Hjulle
我更改了grep函数使用rg,但使用grep --version命令时,它没有像rg --version那样产生相似的输出。为什么?! @Hjulle - Pranav
@Pranav 你运行的命令序列是:alias grep=rgfuncsave grepgrep --version 吗? - Hjulle
@Hjulle 是的,我做了。目前,我已经按照下面的解决方案编辑了config.fish文件。它起作用了。现在我可以执行grep --version并查看rg --version的结果。 - Pranav

65

为了后人,fish 别名只是函数:

$ alias foo="echo bar"
$ type foo
foo is a function with definition
function foo
    echo bar $argv; 
end

删除它

$ unalias foo
/usr/bin/unalias: line 2: unalias: foo: not found
$ functions -e foo
$ type foo
type: Could not find “foo”

11
创建函数后,您可以执行funcsave foo。这将把函数保存到~/.config/fish/functions/foo.fish中,在新会话中第一次调用函数时,fish将自动加载它。 - Lucretiel
2
“alias foo="echo bar"” 是目前最简单的解决方案。 - Ronnie
在Fish 3.2.0中不支持unalias命令。 - niid
1
它在fish中从未可用过,这就是为什么我演示它会抛出一个错误。 - glenn jackman

33

28

fish 通过在 ~/.config/fish/config.fish 中执行命令来启动。如果该文件不存在,您可以创建它:

vim ~/.config/fish/config.fish

并使用 :wq 命令保存。

步骤1. 创建配置文件(如 .bashrc)

config.fish

步骤2. 就像这样编写您的别名;

alias rm="rm -i"


在 fish 配置文件中编写代码对我很有效。我想知道为什么 fish 函数没有给我期望的结果。 - Pranav

21

我知道目前已经有11个答案,它们都可行,但在2022年(过去几年也是如此),大多数都不够优秀。

3.0b1 版本以来的所有更新、最新、当前回答:

  • The quickest and best way to do what is requested in this question is:

    alias -s <aliasname> "command(s)" # Or --save
    

    Important: Simply do this one time per alias at the command-line. Do not add it to your startup config.

  • To list existing aliases which have been defined this way (since fish 2.5b1):

    alias
    
  • To edit an alias created this way:

    funced -s <aliasname> # or --save
    
  • To remove an alias defined this way (since fish 3.4.0):

    functions -e <aliasname> # or --erase
    funcsave <aliasname>
    

    Note that since 3.4.0 was only released a few weeks ago, I'll include the commands that work in previous versions as well:

    functions -e <aliasname> # or --erase
    rm ~/.config/fish/functions/<aliasname>.fish
    

    Ironically, you may even want to alias this into unalias. You'll need to first alias -s unalias the functions -e ... part, then funced -s unalias again to add the rm ....


请注意,@nemanja的答案包括alias -s命令,但没有详细说明。尽管如此,由于它比我的答案更早,如果它成为被接受的答案,我也不介意。然而,当前被接受的答案有点过时。虽然从理论上讲可以进行编辑,但必要的更改,依我看来,会创建一个不同的答案,这是我们不应该做的。
虽然@nemanja的答案是当前fish版本的最佳解决方案,但我写这篇独立答案是为了:
  • 更详细地介绍为什么('alias -s`)是最佳解决方案。
  • 更详细地介绍为什么其他答案在当前fish版本下不太理想。
  • 提供关于编辑和删除以这种方式定义的别名的附加信息。

为什么上述方法比其他答案更好的详细解释

首先,需要理解的是,正如前Fish Shell贡献者Glenn Jackman在这个答案中提到的那样,Fish Shell中的alias命令只是创建函数的语法糖。

然而,当您以这种方式定义别名时,它只在内存中定义。它不会被持久化。这项功能是在该答案编写后不久添加的。

过时的方法#1

有了这个理解,目前被接受的答案从2010年开始就有一些问题。

首先,您真的不应该在配置文件中定义您的别名。这可能在2010年是正确的,但即使那时,我认为Fish也支持函数/别名的惰性加载,这是一个更好的选择。在启动配置文件中定义函数/别名是“bash/zsh的方式”。Fish比那更好...

将Fish与Bash和Zsh区分开来的(许多)特点之一是惰性加载。在这种情况下,惰性是好的。您需要惰性加载(好吧,也许不是需要),但无论如何...

正如原始问题所提到的,您可以在~/.config/fish/functions/中定义函数,尽管这是一个目录而不是文件。请注意,如果已定义该变量,则此目录将为$XDG_CONFIG_HOME/fish/functions

该目录中的函数会被惰性加载。

惰性加载意味着:

  • Fish在启动时不会加载别名/函数的任何部分。这可以显著加快启动时间,特别是如果您有许多别名和/或复杂函数,或者可能正在运行较慢的系统/虚拟机/共享CPU主机。

  • 除了名称(用于查找)之外,函数的任何部分都不会被加载到内存中,直到使用它为止。

  • 只有在第一次使用functionname调用函数时,Fish才会从~/.config/fish/functions/<functionname.fish>惰性加载函数。

这将会有多大的改进取决于许多因素,但就我个人而言,我一直寻找简单的方法来优化我的配置。其中一个主要因素是随着我添加功能、函数等内容,Zsh配置启动变得越来越慢。我们已经切换到了一个更好的 shell(在我们看来),那为什么不利用其改进的功能呢?
这个懒加载听起来可能很复杂,但实际上它几乎与 alias -s 命令完全相同,而且不需要任何额外的努力。
此外,alias 命令还进一步自动为您的函数添加了 --wraps <original_command> 参数,以便您获得补全的附加好处。 它还添加了一个 --description,用于将函数描述为“别名”。 因此,只需运行:
alias

...这本身将为您提供所有以此方式定义的函数/别名的列表。

其他答案

另外三个 独立的 答案 也都提到使用~/.config.fish/config.fish,无论是使用function声明还是alias命令。

与原始答案一样,这是做事情的次优方法。这意味着每次启动新的shell时都会处理和加载您的别名/函数。

我建议您利用惰性加载。

mkalias函数

@Mike的答案 定义了一个创建并保存别名的mkalias函数。这是一个非常好的解决方案(在我看来应该得到更多赞),但它早于fish 3.0发布,后者添加了alias --save/-s,现在可以完成同样的工作。

abbr命令

@TobiasMühl的答案 建议使用abbr命令,这是一个合理的替代方案。但是,请注意,alias确实处理自动补全,并且基本上与该答案中给出的abbr示例相同。

alias -s gco "git checkout"

完成将基于git checkout,就像它是一个扩展缩写一样。

在某些情况下,由于缩写名称打字后立即按下Space进行扩展,因此完成可能更加准确。

这是fish中缩写和别名之间的根本区别之一。缩写在提示符处扩展;别名则不会。

另一个区别是,缩写存储在变量中,这些变量在shell启动时(无论是通用还是全局/配置)被处理/加载。如上所述,别名是惰性加载的。

还有一个区别是,由于别名是函数,因此可以更加复杂。例如,我将我的ls设置为exa,并将输出传输到bat。这在缩写中是不可能定义的。

话虽如此,再次提醒,缩写是在fish中考虑使用的功能。我计划将我的一些别名转换为缩写,因为我有一些需要在扩展后更改参数的情况;这在未扩展的别名中是不可能的。


哪个文件用于定义fish别名? - SL5net
1
@SL5net 抱歉 - 我不理解你问题的背景。你能重新表述一下吗?谢谢! - NotTheDr01ds
现在我期望得到一个好的答案,例如:~/.config/fish/config.fish 是配置 fish 的一个好地方。 - SL5net
1
@SL5net 我的回答已经相当详细地涵盖了这一点。你 不应该 在文件中定义它们,而应该使用 alias -s <aliasname> "command(s)" 在命令行上 定义它们,只需定义一次即可。这将在 ~/.config/fish/functions 中创建与每个别名相对应的函数,这些函数将在需要时进行惰性加载。 - NotTheDr01ds
如果我想将我的别名复制到另一台机器上怎么办? 我应该复制整个~/.config/fish/functions目录而不是一个简单的配置文件吗? - Dimitri Lesnoff
1
@DimitriLesnoff 无论哪种方式,但是我确实将我的函数目录维护在一个git存储库中,这样可以轻松地在多个系统之间保持同步。您也可以维护一个单独的文件,通过多个alias --save ...命令来创建别名。将它们全部放在一个文件中可以工作,但如上所述,在这种情况下它们都会在启动时加载。 - NotTheDr01ds

16

将您的文件保存为~/.config/fish/functions/{some_function_name}.fish,当您启动Fish时它们应该会自动加载。


1
实际上,当您启动fish时,它们不会被“autoloaded”,而是在第一次使用时进行“lazy loaded”。换句话说,在给定的shell中首次调用{some_function_name}之前,它们什么也不做。此时,fish会在函数路径中搜索{some_function_name}.fish,加载该函数(该函数也必须命名为{some_function_name}),然后执行它。我不确定这是否是自答案最初编写以来行为上的变化,但我认为它一直都是这样工作的。 - NotTheDr01ds

15
  1. 如果~/.config/fish/中没有config.fish,则创建它。
  2. 你可以在这里编写你的函数。function 名称; 命令; end

13

为了正确加载从~/.config/fish/functions导入的函数,您可以设置每个文件仅包含一个函数,并将文件命名为函数名称+ .fish扩展名。

这样,在打开的终端中更改文件内容会重新加载函数(请注意,可能会出现一些延迟,约1-5秒)。

如果您通过命令行编辑,则可以通过该方式实现。

function name; function_content; end

然后

funcsave name

您在控制台中有用户定义的函数和自定义函数,它们以相同的顺序排列。


7
@bozhidar-batsov 提供了一个非常完备的答案,帮助人们理解fish中alias/function的内部工作原理。阅读fish文档中有一个-s标记也非常方便,它可以自动将由别名创建的函数保存到你的fish配置目录中,使用funcsave命令。例如定义并保存别名的一行解决方案:alias cl 'clear' -s。立即在所有会话中生效并持久化。导航到~/.config/fish/functions/目录,你会看到一个cl.fish文件。
# Defined via `source`
function cl --wraps=clear --description 'alias cl clear'
  clear $argv;
end

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接