Skip to content

Instantly share code, notes, and snippets.

@ficapy
Created January 6, 2025 07:05
Show Gist options
  • Save ficapy/2bb6384d2de769e94b55be5daeea6e3c to your computer and use it in GitHub Desktop.
Save ficapy/2bb6384d2de769e94b55be5daeea6e3c to your computer and use it in GitHub Desktop.

下面是对 Fish Shell 中几种设置环境变量(或 Shell 变量)方式的总结、区别以及在何种场景使用的简要说明:


1. 按照作用域(scope)进行设置

Fish 中的变量具有不同的作用域(scope)。同名变量可以同时存在于多个作用域中,Fish 会使用最窄的作用域优先。通过 set 命令配合不同选项,可显式指定创建或修改某个作用域的变量:

  1. Local(-l--local

    • 在当前代码块或函数内生效,离开代码块或函数后自动销毁
    • 在函数外部直接使用 set -l,等效于 function scope(见下文)
    • 使用场景:需要在短时间内(如在一个函数内部或一个小块代码里)使用临时变量,不希望污染全局
  2. Function(-f--function

    • 在函数作用域中可见,函数执行结束后自动销毁
    • 使用场景:和 local 类似,但特别强调这是在一个函数中使用的变量(例如想显式指定“只在函数存活”),避免变量在函数外可见
  3. Global(-g--global

    • 在当前 Shell 会话中可见,离开 Shell 会话后即失效
    • 使用场景:需要在整个 Shell 会话范围内随时可访问的变量,比如本地 Session 内的配置信息(如 EDITORPAGER 等),但并不想在多个 Shell 之间共享
  4. Universal(-U--universal

    • 在同一台机器上、同一用户下的所有 Fish 会话间同步存在,并且会在下次重启 Shell 时继续生效
    • 使用场景:希望在一个用户的所有 Fish 实例间共享,并且在重启后都能生效的变量(例如长期的环境变量、常用路径等)

注意

  • 当你未显式指定 -l/-f/-g/-U,但变量已经存在某个作用域,会默认沿用它已经存在的作用域。
  • 若变量名在所有作用域中都不存在,且未显式指定作用域,则会在函数内创建 function-scoped 变量,若不在函数中则默认为 global 作用域。

2. 是否导出到环境(export / unexport)

Fish 中除了决定变量属于哪个作用域外,还可以决定它是不是要导出为环境变量。导出后,子进程也能访问到它。可用以下方式控制:

  1. --export-x
    • 令该变量导出到环境,子进程可访问到
  2. --unexport-u
    • 令该变量不导出到环境

使用场景

  • 需要让后续命令(或外部脚本、子进程)感知到某些配置信息时,用 --export
  • 如果仅在当前 Shell 会话或函数内自己用,不想暴露给外部进程,就不要导出它。

3. 是否作为路径变量(path variable)

Fish 中可以指定某个变量是否被视为“路径变量”,它会自动以冒号(:)拆分、重组:

  1. --path
    • 将某变量视为路径变量,将自动以 : 拆分和处理。例如当你执行 echo "$PATH" 时会用 : 连接所有路径值
  2. --unpath
    • 取消把该变量作为路径变量处理

使用场景

  • 例如需要手动维护自己的 PATH,或类似用冒号分割的路径列表时,可以使用 --path 自动帮你处理拼接/拆分。
  • 变量名以 “PATH” 结尾时(如 LD_LIBRARY_PATH),Fish 通常会默认将它视作路径变量。

4. 追加 / 前置 变量值

若想往已有的变量追加或前置(prepend)一些值,可使用:

  1. 追加(-a--append

    set -a foo new_value
    • 会在现有的 foo 列表结尾处追加 new_value
  2. 前置(-p--prepend

    set -p foo first_value
    • 会将 first_value 放在现有的 foo 列表开头

使用场景

  • 动态拼接路径或其他列表值;如要在 PATH 最前面插入某个自定义路径,可用 -p PATH /custom/bin

5. 列表切片或单个元素赋值

Fish 允许变量存储多个值,且可以用索引(从 1 开始,负数表示从末尾往前)修改或访问列表中的某些元素:

# 修改第四个元素
set PATH[4] ~/bin
# 若是负数索引则从末尾开始计算,如:PATH[-1] 表示列表最后一个元素

使用场景

  • 在不改变整个列表的前提下,对其中某个或某几个元素进行替换、更新等。

6. 查询(Query)和删除(Erase)变量

  1. 查询(-q--query

    if set -q foo
        echo "foo 已经定义"
    else
        echo "foo 未定义"
    end
    • 查询一个变量(或变量中的某个索引值)是否已被定义
    • 返回码是“未找到变量的数量”,可结合 if 判断
  2. 删除(-e--erase

    set -e foo
    • 删除指定的变量
    • 如果带索引 foo[2],则只删除列表中第二项,而不是整个变量
    • 如果想同时删除全局和 universal 范围: set -e -Ug foo

使用场景

  • 脚本中先查询再执行特定逻辑
  • 删除局部/全局变量释放资源,或者清理旧的环境变量

7. 一次性为命令设置变量

Fish 支持和其他 Shell 类似的“为单个命令暂时设置变量”语法:

VAR=VALUE command

这在内部相当于:

begin
    set -lx VAR VALUE
    command
end
  • -l 表示局部作用域;-x 表示导出
  • 命令执行完后该变量就失效

使用场景

  • 想让某个命令以临时变量进行运行,而不污染当前 Shell 环境。例如临时把 HOME 指定为某个测试路径。

8. 设置变量并保留原有的退出状态码

在 Fish 里,执行 set 并不会改变 $status,但如果执行了命令替换 (command) 仍可能会影响 $status。例如:

# 若执行 false 命令后,$status 会变成 1
false
set foo bar
echo $status  # 依然是 1

使用场景

  • 在脚本中,如果你需要捕获某个命令的返回值并且后续使用它,要了解这一特性,以免对 Shell 状态码判断造成干扰。

总结

  1. 作用域(scope):决定变量只在函数、局部、当前 Shell 还是所有 Fish 会话中存在;
  2. 是否导出(export):决定变量是否可被子进程读取;
  3. 路径变量(path variable):将变量内容视作用 : 分割的路径列表;
  4. 追加 / 前置:对已有变量值执行追加或前置操作;
  5. 列表切片:对变量的特定索引内容进行赋值/访问;
  6. 查询 / 删除:查看变量是否存在或删除变量/变量值;
  7. 一次性变量:临时为某条命令分配变量,不影响当前会话环境;
  8. 状态码传递set 不会覆盖 $status,但命令替换 (some_command) 会。

这些特性可灵活配合使用,满足 Fish Shell 脚本与环境管理的各种需求。根据你所编写脚本或需要的持久化程度、共享范围来选择合适的作用域导出方式,并利用追加、切片、删除等功能进行更细粒度的控制。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment