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.

Revisions

  1. ficapy created this gist Jan 6, 2025.
    173 changes: 173 additions & 0 deletions fish_set.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,173 @@
    下面是对 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 内的配置信息(如 `EDITOR``PAGER` 等),但并不想在多个 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`**
    ```fish
    set -a foo new_value
    ```
    - 会在现有的 `foo` 列表结尾处追加 `new_value`

    2. **前置(`-p``--prepend`**
    ```fish
    set -p foo first_value
    ```
    - 会将 `first_value` 放在现有的 `foo` 列表开头

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

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

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

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

    > **使用场景**
    > - 在不改变整个列表的前提下,对其中某个或某几个元素进行替换、更新等。
    ---

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

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

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

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

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

    Fish 支持和其他 Shell 类似的“为单个命令暂时设置变量”语法:
    ```fish
    VAR=VALUE command
    ```
    这在内部相当于:
    ```fish
    begin
    set -lx VAR VALUE
    command
    end
    ```
    - `-l` 表示局部作用域;`-x` 表示导出
    - 命令执行完后该变量就失效

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

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

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

    ```fish
    # 若执行 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 脚本与环境管理的各种需求。根据你所编写脚本或需要的持久化程度、共享范围来选择合适的**作用域****导出方式**,并利用追加、切片、删除等功能进行更细粒度的控制。