Gitlab-CI 与 Shell 会话模式
之前的文章中介绍过,iOS 常用的 Gitlab-CI 执行器是 shell,因为打包时只能使用这个。
今天将包管理工具迁到 mise 时遇到了一些和 shell 有关的问题,涉及到一些之前的知识盲区,遂记录一下。
本文的内容和 mise 无关,只是工具迁移时引出了本文涉及到的问题和知识盲区。对工具感兴趣的朋友可以点击上面的链接查看相关内容。
Shell 会话模式
先介绍一下 Shell 的几种会话模式。
我们都知道 macOS 的 默认终端环境是 zsh,zsh 有多个配套的文件,包含 ~/.zshrc
、.zprofile
等。另一个比较常见的是 bash,可使用的配置文件有 ~/.bash_profile
、~/.bashrc
等。
之前我只模糊的知道有这些文件,可以在其中写入一些内容,然后启动终端后就会自动加载这些文件,却从来没有关注过 什么时候会加载哪个文件。这就涉及到 “Shell 会话模式” 这个概念。
“Shell 会话模式”是指用户启动会话时 shell(例如 bash、zsh 或其他命令行解释器)可以运行的不同方式。每种模式都规定了 shell 的行为方式、加载的初始化文件以及处理命令的方式。
此会话模式主要围绕两个概念:“是否是交互式” 以及 “是否登录”。这两种概念两两组合,诞生四种会话模式。
- 是否是交互式:指定用户是否可以通过键入命令直接与 shell 交互。shell 会等待用户输入并根据输入的命令提供输出。
- 是否登录:指开启会话时用户是否登录。
举几个例子:
- 交互式:打开 macOS 中的终端,此时我们可以在里面输入命令,与 shell 交互。
- 非交互式:Gitlab-CI 执行 script 时,就是非交互式。我们知道执行过程中我们没有办法做任何事,包括输入设备密码,say yes 等。
- 登录:通过 ssh 连接服务器,此时需要我们输入用户名密码。又或者执行命令时携带了
| /bin/bash --login
参数。 - 非登录:打开 macOS 的终端,默认是非登录的。又或者从一个已经登录了的终端中,使用
bash
或其他命令开启了新的终端窗口,这些也是非登录式的。
那么在不同的登录模式下,shell 会加载的配置文件其实是不同的:
会话类型 | .bash_profile |
.bashrc |
.zprofile |
.zshrc |
---|---|---|---|---|
交互式登录 | ✅ | ❌ | ✅ | ❌ |
交互式非登录 | ❌ | ✅ | ❌ | ✅ |
非交互式登录 | ✅ | ❌ | ❌ | ❌ |
非交互式非登录 | ❌ | ❌ | ❌ | ❌ |
如果使用 bash,那么还有一个可能会使用的配置文件:
~/.profile
。它的作用和~/.bash_profile
类似,仅当.bash_profile
不存在时,会尝试加载.profile
。另外,有的时候.bash_profile
中会有命令,同时加载.profile
。
而 zsh 默认是不会尝试加载.profile
的。
Gitlab-CI 的 script
Gitlab-CI 的文档有列举出它所支持的 shell 种类,这里我们看默认的 bash。
贴一下文档中关于如何执行
script
的示例# This command is used if the build should be executed in context of another user (the shell executor) cat generated-bash-script | su --shell /bin/bash --login user # This command is used if the build should be executed using the current user, but in a login environment cat generated-bash-script | /bin/bash --login # This command is used if the build should be executed in a Docker environment cat generated-bash-script | /bin/bash
从文档中可以看到,不论哪种方式,Gitlab-CI 都是使用 /bin/bash
环境执行的 script
中定义的脚本,并且在非 Docker 环境下,会携带 --login
参数,也就是说此时使用的是 “非交互式登录 Shell”,回看上面的表格,.bash_profile
文件会被加载。
此时就需要注意了,因为 macOS 默认的终端是 zsh,所以我们在编写脚本的时候,很可能会习惯性地将配置写入到 .zprofile
或者 .zshrc
文件中,但是回到 Gitlab-CI 中就会发现不生效,原因就是脚本的执行环境不同。