下面是对 Fish Shell 中几种设置环境变量(或 Shell 变量)方式的总结、区别以及在何种场景使用的简要说明:
Fish 中的变量具有不同的作用域(scope)。同名变量可以同时存在于多个作用域中,Fish 会使用最窄的作用域优先。通过 set
命令配合不同选项,可显式指定创建或修改某个作用域的变量:
-
Local(
-l
或--local
)- 在当前代码块或函数内生效,离开代码块或函数后自动销毁
- 在函数外部直接使用
set -l
,等效于 function scope(见下文) - 使用场景:需要在短时间内(如在一个函数内部或一个小块代码里)使用临时变量,不希望污染全局
-
Function(
-f
或--function
)- 在函数作用域中可见,函数执行结束后自动销毁
- 使用场景:和 local 类似,但特别强调这是在一个函数中使用的变量(例如想显式指定“只在函数存活”),避免变量在函数外可见
-
Global(
-g
或--global
)- 在当前 Shell 会话中可见,离开 Shell 会话后即失效
- 使用场景:需要在整个 Shell 会话范围内随时可访问的变量,比如本地 Session 内的配置信息(如
EDITOR
、PAGER
等),但并不想在多个 Shell 之间共享
-
Universal(
-U
或--universal
)- 在同一台机器上、同一用户下的所有 Fish 会话间同步存在,并且会在下次重启 Shell 时继续生效
- 使用场景:希望在一个用户的所有 Fish 实例间共享,并且在重启后都能生效的变量(例如长期的环境变量、常用路径等)
注意:
- 当你未显式指定
-l/-f/-g/-U
,但变量已经存在某个作用域,会默认沿用它已经存在的作用域。- 若变量名在所有作用域中都不存在,且未显式指定作用域,则会在函数内创建 function-scoped 变量,若不在函数中则默认为 global 作用域。
Fish 中除了决定变量属于哪个作用域外,还可以决定它是不是要导出为环境变量。导出后,子进程也能访问到它。可用以下方式控制:
--export
或-x
- 令该变量导出到环境,子进程可访问到
--unexport
或-u
- 令该变量不导出到环境
使用场景:
- 需要让后续命令(或外部脚本、子进程)感知到某些配置信息时,用
--export
。- 如果仅在当前 Shell 会话或函数内自己用,不想暴露给外部进程,就不要导出它。
Fish 中可以指定某个变量是否被视为“路径变量”,它会自动以冒号(:
)拆分、重组:
--path
- 将某变量视为路径变量,将自动以
:
拆分和处理。例如当你执行echo "$PATH"
时会用:
连接所有路径值
- 将某变量视为路径变量,将自动以
--unpath
- 取消把该变量作为路径变量处理
使用场景:
- 例如需要手动维护自己的
PATH
,或类似用冒号分割的路径列表时,可以使用--path
自动帮你处理拼接/拆分。- 变量名以 “PATH” 结尾时(如
LD_LIBRARY_PATH
),Fish 通常会默认将它视作路径变量。
若想往已有的变量追加或前置(prepend)一些值,可使用:
-
追加(
-a
或--append
)set -a foo new_value
- 会在现有的
foo
列表结尾处追加new_value
- 会在现有的
-
前置(
-p
或--prepend
)set -p foo first_value
- 会将
first_value
放在现有的foo
列表开头
- 会将
使用场景:
- 动态拼接路径或其他列表值;如要在 PATH 最前面插入某个自定义路径,可用
-p PATH /custom/bin
。
Fish 允许变量存储多个值,且可以用索引(从 1 开始,负数表示从末尾往前)修改或访问列表中的某些元素:
# 修改第四个元素
set PATH[4] ~/bin
# 若是负数索引则从末尾开始计算,如:PATH[-1] 表示列表最后一个元素
使用场景:
- 在不改变整个列表的前提下,对其中某个或某几个元素进行替换、更新等。
-
查询(
-q
或--query
)if set -q foo echo "foo 已经定义" else echo "foo 未定义" end
- 查询一个变量(或变量中的某个索引值)是否已被定义
- 返回码是“未找到变量的数量”,可结合 if 判断
-
删除(
-e
或--erase
)set -e foo
- 删除指定的变量
- 如果带索引
foo[2]
,则只删除列表中第二项,而不是整个变量 - 如果想同时删除全局和 universal 范围:
set -e -Ug foo
使用场景:
- 脚本中先查询再执行特定逻辑
- 删除局部/全局变量释放资源,或者清理旧的环境变量
Fish 支持和其他 Shell 类似的“为单个命令暂时设置变量”语法:
VAR=VALUE command
这在内部相当于:
begin
set -lx VAR VALUE
command
end
-l
表示局部作用域;-x
表示导出- 命令执行完后该变量就失效
使用场景:
- 想让某个命令以临时变量进行运行,而不污染当前 Shell 环境。例如临时把
HOME
指定为某个测试路径。
在 Fish 里,执行 set
并不会改变 $status
,但如果执行了命令替换 (command)
仍可能会影响 $status
。例如:
# 若执行 false 命令后,$status 会变成 1
false
set foo bar
echo $status # 依然是 1
使用场景:
- 在脚本中,如果你需要捕获某个命令的返回值并且后续使用它,要了解这一特性,以免对 Shell 状态码判断造成干扰。
- 作用域(scope):决定变量只在函数、局部、当前 Shell 还是所有 Fish 会话中存在;
- 是否导出(export):决定变量是否可被子进程读取;
- 路径变量(path variable):将变量内容视作用
:
分割的路径列表; - 追加 / 前置:对已有变量值执行追加或前置操作;
- 列表切片:对变量的特定索引内容进行赋值/访问;
- 查询 / 删除:查看变量是否存在或删除变量/变量值;
- 一次性变量:临时为某条命令分配变量,不影响当前会话环境;
- 状态码传递:
set
不会覆盖$status
,但命令替换(some_command)
会。
这些特性可灵活配合使用,满足 Fish Shell 脚本与环境管理的各种需求。根据你所编写脚本或需要的持久化程度、共享范围来选择合适的作用域和导出方式,并利用追加、切片、删除等功能进行更细粒度的控制。