fish使用.md

色彩

命令为红色为无效命令,命令为蓝色为有效命令

image-20240510142521941

有效路径有下划线,无效路径没有下划线

image-20240510142551160

命令提示

image-20240510142725032

->Ctrl + F可以采纳全部建议

ALT + -> 可以采纳部分建议

fish配置文件

fish的一个配置文件~/.config/fish/config.fish,fish启动时会自动加载这个文件,类似于bash中的.bashrc文件。

fish语法及使用

四种变量

https://fishshell.com/docs/current/language.html#variables-universal

https://fishshell.com/docs/current/language.html#variables-scope

There are four kinds of variables in fish: universal, global, function and local variables.

  • Universal variables are shared between all fish sessions a user is running on one computer. They are stored on disk and persist even after reboot.

  • Global variables are specific to the current fish session. They can be erased by explicitly requesting set -e.

    1
    2
    3
    4
    5
    6
    7
    set -gx py python                                                                                                                                                                                                       
    echo $py
    python

    # 关闭终端后重启
    echo $py
    # 无输出
  • Function variables are specific to the currently executing function. They are erased (“go out of scope”) when the current function ends. Outside of a function, they don’t go out of scope.

  • Local variables are specific to the current block of commands, and automatically erased when a specific block goes out of scope. A block of commands is a series of commands that begins with one of the commands for, while , if, function, begin or switch, and ends with the command end. Outside of a block, this is the same as the function scope.

Variables can be explicitly set to be universal with the -U or --universal switch, global with -g or --global, function-scoped with -f or --function and local to the current block with -l or --local. The scoping rules when creating or updating a variable are:

  • When a scope is explicitly given, it will be used. If a variable of the same name exists in a different scope, that variable will not be changed.(当明确指定范围时,将使用它。如果不同范围内存在同名变量,则不会更改其他范围的同名变量)
  • When no scope is given, but a variable of that name exists, the variable of the smallest scope will be modified. The scope will not be changed.(未指定范围但存在同名变量时,将修改最小范围的变量。范围不会更改)
  • When no scope is given and no variable of that name exists, the variable is created in function scope if inside a function, or global scope if no function is executing.(未指定范围且不存在同名变量时,如果变量位于函数内,则在函数范围内创建该变量;如果未执行任何函数,则在全局范围内创建该变量。)

There can be many variables with the same name, but different scopes. When you use a variable, the smallest scoped variable of that name will be used. If a local variable exists, it will be used instead of the global or universal variable of the same name.

可以有多个同名但作用域不同的变量。当你 使用变量 时,将使用该名称的最小作用域变量。如果存在局部变量,则将使用该局部变量,而不是同名的全局或通用变量。

应用场景:

Typically inside functions you should use local scope:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function something
set -l file /path/to/my/file # local variable
if not test -e "$file"
set file /path/to/my/otherfile
end
end

# or

function something
if test -e /path/to/my/file
set -f file /path/to/my/file # functional variable
else
set -f file /path/to/my/otherfile
end
end

If you want to set something in config.fish, or set something in a function and have it available for the rest of the session, global scope is a good choice:

只在当前shell session生效,关闭当前shell session后失效

1
2
3
4
5
6
7
8
9
10
11
12
# Don't shorten the working directory in the prompt
set -g fish_prompt_pwd_dir_length 0

# Set my preferred cursor style:
function setcursors
set -g fish_cursor_default block
set -g fish_cursor_insert line
set -g fish_cursor_visual underscore
end

# Set my language
set -gx LANG de_DE.UTF-8

If you want to set some personal customization, universal variables are nice:(永久保存,关机后也存在)

1
2
# Typically you'd run this interactively, fish takes care of keeping it.
set -U fish_color_autosuggestion 555

关于universal variables,fish文档有点冲突

https://fishshell.com/docs/current/language.html#variables-scope中描述Universal variables are shared between all fish sessions a user is running on one computer,是a user,即仅对一个用户有效

https://fishshell.com/docs/current/language.html#variables-universal中描述Universal variables are variables that are shared between all the user’s fish sessions on the computer,是all user,对所有用户有效

测试了一下:

1
2
3
4
5
6
7
8
9
set -U fish_color_autosuggestion 555                                                                           

echo $fish_color_autosuggestion
555

❯ su # change to root

echo $fish_color_autosuggestion
brblack

应该是one user

【注意】

  • 不要将universal variables 附加到 config.fish 文件中,因为这些变量会随着每个新 shell 实例而变长。相反,只需在命令行运行一次 set -Ux 即可。从 Fish 3.0 开始,通用变量将存储在文件 ~/.config/fish/fish_variables 中。在之前的版本中,它是 ~/.config/fish/fishd.MACHINE_ID,其中 MACHINE_ID 通常是 MAC 地址。参考https://stackoverflow.com/questions/25632846/how-to-set-environment-variables-in-fish-shell
  • 不要将global variables附加到 config.fish 中,因为global variables的本意是当前shell session有效的变量,如果将其添加到config.fish中,那么所有shell session中都会加载config.fish中的global variables

添加路径到PATH变量

fish_add_path命令

https://fishshell.com/docs/current/cmds/fish_add_path.html

fish_add_path is a simple way to add more components to fish’s PATH. It does this by adding the components either to $fish_user_paths or directly to PATH (if the --path switch is given).

Components are added in the order they are given, and they are prepended(前置) to the path unless --append is given (if fish_user_paths, which is itself prepended to PATH, so they still stay ahead of the system paths).

PATH的前面

-a or –append

Add components to the end of the variable.

-m or –move

Move already-existing components to the place they would be added - by default they would be left in place and not added again.(如果组件已经存在,则不会再次添加,除非给出 –move 开关,否则组件将保留在同一位置。)

-U or –universal

Use a universal fish_user_paths - this is the default if it doesn’t already exist.(如不不存在参数,则默认为-U)

-P or –path

Manipulate PATH directly.(直接加入fish_user_paths)

例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# I just installed mycoolthing and need to add it to the path to use it.
> fish_add_path /opt/mycoolthing/bin

# I want my ~/.local/bin to be checked first.
> fish_add_path -m ~/.local/bin

# I prefer using a global fish_user_paths
> fish_add_path -g ~/.local/bin ~/.otherbin /usr/local/sbin

# I want to append to the entire $PATH because this directory contains fallbacks
> fish_add_path -aP /opt/fallback/bin

# I want to add the bin/ directory of my current $PWD (say /home/nemo/)
> fish_add_path -v bin/
set fish_user_paths /home/nemo/bin /usr/bin /home/nemo/.local/bin

# I have installed ruby via homebrew
> fish_add_path /usr/local/opt/ruby/bin

设置环境变量(set命令)

set manipulates shell variables.

If both NAME and VALUE are provided, set assigns any values to variable NAME. Variables in fish are lists, multiple values are allowed. One or more variable INDEX can be specified including ranges (not for all options.)

(可以设置多个值,如set -gx py py1 py2 py3)

1
2
3
4
set -gx py python1 python2                                                                                     

echo $py
python1 python2

If no VALUE is given, the variable will be set to the empty list.

If set is ran without arguments, it prints the names and values of all shell variables in sorted order. Passing scope or export flags allows filtering this to only matching variables, so set --local would only show local variables.

With --show, set will describe the given variable names, explaining how they have been defined - in which scope with which values and options.

1
2
3
4
set --show py                                                                                                  (base)
$py: set in global scope, exported, with 2 elements
$py[1]: |python1|
$py[2]: |python2|

With --erase and optionally a scope flag set will erase the matching variable (or the variable of that name in the smallest possible scope).

1
2
3
4
set --erase py  # 删除                                                                                               

set --show py
# 已经被删除,没有输出

四种范围选项:

The following options control variable scope:

  • -U or –universal

    Sets a universal variable. The variable will be immediately available to all the user’s fish instances on the machine, and will be persisted across restarts of the shell.

  • -f or –function

    Sets a variable scoped to the executing function. It is erased when the function ends.

  • -l or –local

    Sets a locally-scoped variable in this block. It is erased when the block ends. Outside of a block, this is the same as –function.

  • -g or –global

    Sets a globally-scoped variable. Global variables are available to all functions running in the same shell. They can be modified or erased.

–export or -x

Causes the specified shell variable to be exported to child processes (making it an “environment variable”).

–unexport or -u

Causes the specified shell variable to NOT be exported to child processes.

使用了-x,变量会被导入子进程

测试

创建test.fish,在shell中执行fish脚本,会开启一个子进程执行fish脚本

1
2
#!/usr/bin/fish
echo $py

不使用-x

1
2
3
4
5
set -g py python                                                                                               
echo $py
python # 当前进程可以输出$py

❯ ./test.fish # 执行test.fish,没有输出,说明没有变量py没有导出给执行shell脚本的子进程

使用-x

1
2
3
4
5
6
7
8
set -gx py python                                                                                             

echo $py
python


❯ ./test.fish # 执行test.fish,有输出,说明没有变量py导出给执行shell脚本的子进程
python

-e or –erase *NAME*[INDEX]删除环境变量

Causes the specified shell variables to be erased. Supports erasing from multiple scopes at once. Individual items in a variable at INDEX in brackets can be specified.

-S or –show查看环境变量

Shows information about the given variables. If no variable names are given then all variables are shown in sorted order. It shows the scopes the given variables are set in, along with the values in each and whether or not it is exported. No other flags can be used with this option.

用的最多的

1
2
3
4
set -Ux key value #全局生效
set -gx key value #当前shell生效
set --erase key # 删除
set --show key # 查看

fish取别名(alias/function)

https://fishshell.com/docs/current/language.html#functions

alias is a simple wrapper for the function builtin, which creates a function wrapping a command. It has similar syntax to POSIX shell alias. For other uses, it is recommended to define a function.

alias会创建一个function,因此学习fish functions

Functions are programs written in the fish syntax. They group together various commands and their arguments using a single name.

For example, here’s a simple function to list directories:

1
2
3
function ll
ls -l $argv
end

The first line tells fish to define a function by the name of ll, so it can be used by simply writing ll on the commandline.

The second line tells fish that the command ls -l $argv should be called when ll is invoked.

$argv is a list variable, which always contains all arguments sent to the function.

In the example above, these are simply passed on to the ls command. The end on the third line ends the definition.

Calling this as ll /tmp/ will end up running ls -l /tmp/, which will list the contents of /tmp.

Fish’s prompt is also defined in a function, called fish_prompt.

Defining aliases

One of the most common uses for functions is to slightly alter the behavior of an already existing command(修改存在的命令行的表现). For example, one might want to redefine the ls command to display colors. The switch for turning on colors on GNU systems is --color=auto. An alias around ls might look like this:

1
2
3
4
function ls
command ls --color=auto $argv
end
COPY

There are a few important things that need to be noted about aliases:

  • Always take care to add the $argv variable to the list of parameters to the wrapped command. This makes sure that if the user specifies any additional parameters to the function, they are passed on to the underlying command.
  • If the alias has the same name as the aliased command, you need to prefix the call to the program with command to tell fish that the function should not call itself, but rather a command with the same name. If you forget to do so, the function would call itself until the end of time. Usually fish is smart enough to figure this out and will refrain from doing so (which is hopefully in your interest).

Autoloading functions(自动加载函数)

Functions can be defined on the commandline or in a configuration file, but they can also be automatically loaded. This has some advantages:

  • An autoloaded function becomes available automatically to all running shells.
  • If the function definition is changed, all running shells will automatically reload the altered version, after a while.
  • Startup time and memory usage is improved, etc.

简单的说,Autoloading functions就是会自动加载,因此在命令行可以直接使用这个函数的函数名

因此,如果有为命令定义别名,或创建新命令,可以使用Autoloading functions,而不是直接在config.fish中添加,由于shell启动会执行config.fish,因此在config.fish中添加会导致fish启动速度减慢。

When fish needs to load a function, it searches through any directories in the list variable $fish_function_path for a file with a name consisting of the name of the function plus the suffix .fish and loads the first it finds.

For example if you try to execute something called banana, fish will go through all directories in $fish_function_path looking for a file called banana.fish and load the first one it finds.

当fish想要加载一个函数xxx时,会查找$fish_function_path(是一个list变量)中所有路径下是否有相应的xxx.fish文件

By default $fish_function_path contains the following:

  • A directory for users to keep their own functions, usually ~/.config/fish/functions (controlled by the XDG_CONFIG_HOME environment variable).
  • A directory for functions for all users on the system, usually /etc/fish/functions (really $__fish_sysconfdir/functions).
  • Directories for other software to put their own functions. These are in the directories under $__fish_user_data_dir (usually ~/.local/share/fish, controlled by the XDG_DATA_HOME environment variable) and in the XDG_DATA_DIRS environment variable, in a subdirectory called fish/vendor_functions.d. The default value for XDG_DATA_DIRS is usually /usr/share/fish/vendor_functions.d and /usr/local/share/fish/vendor_functions.d.
  • The functions shipped with fish, usually installed in /usr/share/fish/functions (really $__fish_data_dir/functions).

If you are unsure, your functions probably belong in ~/.config/fish/functions.

As we’ve explained, autoload files are loaded by name, so, while you can put multiple functions into one file, the file will only be loaded automatically once you try to execute the one that shares the name.

正如我们所解释的,自动加载文件是按名称加载的,因此,虽然您可以将多个函数放入一个文件中,但只有在您尝试执行同名的函数时才会自动加载该文件。

If a file of the right name doesn’t define the function, fish will not read other autoload files, instead it will go on to try builtins and finally commands. This allows masking a function defined later in $fish_function_path, e.g. if your administrator has put something into /etc/fish/functions that you want to skip.

这种设计允许在$fish_function_path路径中存在多个autoload文件,但只会加载与命令名匹配的第一个autoload文件,避免了重复加载相同的函数定义。同时,如果在系统管理员预设的目录(比如/etc/fish/functions)中存在某个函数定义,但用户不想使用它,可以通过在用户自定义的autoload文件中定义同名函数来覆盖系统管理员预设的函数。

alias

alias is a simple wrapper for the function builtin, which creates a function wrapping a command. It has similar syntax to POSIX shell alias. For other uses, it is recommended to define a function.

alias会创建函数

If you want to ease your interactive use, to save typing, consider using an abbreviation instead.

fish marks functions that have been created by alias by including the command used to create them in the function description. You can list alias-created functions by running alias without arguments. They must be erased using functions -e.

  • NAME is the name of the alias
  • DEFINITION is the actual command to execute. alias automatically appends $argv, so that all parameters used with the alias are passed to the actual command.

You cannot create an alias to a function with the same name. Note that spaces need to be escaped in the call to alias just like at the command line, even inside quoted parts.

-s or –save(保存为自动加载文件)

Saves the function created by the alias into your fish configuration directory using funcsave.

funcsave saves a function to a file in the fish configuration directory. This function will be automatically loaded by current and future fish sessions. This can be useful to commit functions created interactively(交互式) for permanent use.

问题解决

ubuntu系统语言为中文,此时Git相关命令的输出也为中文,想要使Git输出为英文,可以用function或alias解决。

创建function解决:

在~/.config/fish/functions目录下,新建git.fish文件(文件名必须为git,参考Autoloading functions中的要求)

文件内容为:

1
2
3
function git
LANG=en_US command git $argv
end

注意:

  • LANG=en_US设置语言
  • command不能省略,否则会提示递归调用git函数,用command表示函数中的git不是一个函数,而是一个命令git

使用alias命令解决

1
2
alias --save git="LANG=en_US command git"                                                                      
funcsave: wrote ~/.config/fish/functions/git.fish # 自动创建了git.fish,并且--save指定了该函数为Autoloading function