{"meta":{"title":"对工作流和操作中的表达式求值","intro":"在 GitHub Actions 中查找有关表达式的信息。","product":"GitHub Actions","breadcrumbs":[{"href":"/zh/actions","title":"GitHub Actions"},{"href":"/zh/actions/reference","title":"参考"},{"href":"/zh/actions/reference/workflows-and-actions","title":"工作流和操作"},{"href":"/zh/actions/reference/workflows-and-actions/expressions","title":"表达式"}],"documentType":"article"},"body":"# 对工作流和操作中的表达式求值\n\n在 GitHub Actions 中查找有关表达式的信息。\n\n## 文本\n\n作为表达式的一部分，可使用 `boolean`、`null`、`number` 或 `string` 数据类型。\n\n| 数据类型             | 文本值                                                                                                           |\n| ---------------- | ------------------------------------------------------------------------------------------------------------- |\n| `boolean`        |                                                                                                               |\n| `true` 或 `false` |                                                                                                               |\n| `null`           | `null`                                                                                                        |\n| `number`         | JSON 支持的任何数字格式。                                                                                               |\n| `string`         | 无需将字符串括在 `${` 和 `}` 中。 但是，如果这样做，则必须在字符串两边使用单引号 (`'`)。 要使用文本单引号，请使用额外的单引号 (`''`) 转义文本单引号。 用双引号 (`\"`) 括起来会引发错误。 |\n\n请注意，在条件中，假值（`false`、`0`、`-0`、`\"\"`、`''`、`null`）被强制转换为 `false`，且真值（`true` 和其他非假值）被强制转换为 `true`。\n\n### 文本示例\n\n```yaml\nenv:\n  myNull: ${{ null }}\n  myBoolean: ${{ false }}\n  myIntegerNumber: ${{ 711 }}\n  myFloatNumber: ${{ -9.2 }}\n  myHexNumber: ${{ 0xff }}\n  myExponentialNumber: ${{ -2.99e-2 }}\n  myString: Mona the Octocat\n  myStringInBraces: ${{ 'It''s open source!' }}\n```\n\n## 运营商\n\n| 操作员               | 说明     |\n| ----------------- | ------ |\n| `( )`             | 逻辑分组   |\n| `[ ]`             | 索引     |\n| `.`               | 属性取消引用 |\n| `!`               | Not    |\n| `<`               | 小于     |\n| `<=`              | 小于或等于  |\n| `>`               | 大于     |\n| `>=`              | 大于或等于  |\n| `==`              | 等于     |\n| `!=`              | 不等于    |\n| `&&`              | 和      |\n| <code>\\|\\|</code> | 或      |\n\n> \\[!NOTE]\n> \\*\n> GitHub 在比较字符串时忽略大小写。\n> \\*\n> `steps.<step_id>.outputs.<output_name>` 计算结果为字符串。\n> 您需要使用特定语法指示 GitHub 对表达式求值，而不是将其视为字符串。 有关详细信息，请参阅 [上下文参考](/zh/actions/reference/workflows-and-actions/contexts#steps-context)。\n>\n> * 对于数值比较，`fromJSON()` 函数可用于将字符串转换为数字。 有关 `fromJSON()` 函数的更多信息，请参阅 [fromJSON](#fromjson)。\n\nGitHub 进行宽松的等式比较。\n\n* 如果类型不匹配， GitHub 将类型强制转换为数字。\n  GitHub 使用以下转换将数据类型转换为数值：\n\n  | 类型   | 结果  |\n  | ---- | --- |\n  | Null | `0` |\n  | 布尔   |     |\n\n`true` 返回 `1` <br />\n`false` 返回 `0` |\n\\| 字符串  | 从任何合法的 JSON 数字格式进行分析，否则为 `NaN`。 <br /> 注意：空字符串返回 `0`。 |\n\\| Array   | `NaN` |\n\\| 对象  | `NaN` |\n\n* 当 `NaN` 是任何关系比较（`>`、`<`、`>=`、`<=`）的操作数之一，结果始终为 `false`。 有关更多信息，请参阅 [NaN Mozilla 文档](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/NaN)。\n* GitHub 在比较字符串时忽略大小写。\n* 对象和数组仅在为同一实例时才视为相等。\n\n## Functions\n\nGitHub 提供了一组可在表达式中使用的内置函数。 有些函数抛出值到字符串以进行比较。\nGitHub 通过以下转换将数据类型转换为字符串：\n\n| 类型                   | 结果             |\n| -------------------- | -------------- |\n| Null                 | `''`           |\n| 布尔                   |                |\n| `'true'` 或 `'false'` |                |\n| Number               | 十进制格式，对大数字使用指数 |\n| Array                | 数组不转换为字符串      |\n| 对象                   | 对象不转换为字符串      |\n\n### contains\n\n`contains( search, item )`\n\n如果 `true` 包含 `search`，则返回 `item`。 如果 `search` 是一个数组，`true` 是数组中的一个元素，此函数将返回 `item`。 如果 `search` 是一个字符串，`true` 是 `item` 的 substring，此函数将返回 `search`。 此函数不区分大小写。 抛出值到字符串。\n\n#### 使用字符串的示例\n\n`contains('Hello world', 'llo')` 返回 `true`。\n\n#### 使用对象筛选器的示例\n\n如果与事件相关的议题带有“bug”标签，则 `contains(github.event.issue.labels.*.name, 'bug')` 返回 `true`。\n\n有关更多信息，请参阅[对象筛选器](#object-filters)。\n\n#### 匹配字符串数组的示例\n\n可以将 `github.event_name == \"push\" || github.event_name == \"pull_request\"` 与 `contains()` 配合使用来检查字符串数组是否包含 `fromJSON()`，而不是编写 `item`。\n\n例如，如果 `contains(fromJSON('[\"push\", \"pull_request\"]'), github.event_name)` 是“push”或“pull\\_request”，`true` 便会返回 `github.event_name`。\n\n### startsWith\n\n`startsWith( searchString, searchValue )`\n\n如果 `true` 以 `searchString` 开头，将返回 `searchValue`。 此函数不区分大小写。 抛出值到字符串。\n\n#### `startsWith` 的示例\n\n`startsWith('Hello world', 'He')` 返回 `true`。\n\n### endsWith\n\n`endsWith( searchString, searchValue )`\n\n如果 `true` 以 `searchString` 结尾，则返回 `searchValue`。 此函数不区分大小写。 抛出值到字符串。\n\n#### `endsWith` 的示例\n\n`endsWith('Hello world', 'ld')` 返回 `true`。\n\n### 格式\n\n`format( string, replaceValue0, replaceValue1, ..., replaceValueN)`\n\n将 `string` 中的值替换为变量 `replaceValueN`。\n`string` 中的变量是使用 `{N}` 语法指定的，其中 `N` 是一个整数。 必须至少指定一个 `replaceValue` 和 `string`。 可使用的变量 (`replaceValueN`) 的数量没有上限。 使用双小括号逸出大括号。\n\n#### `format` 的示例\n\n```javascript\nformat('Hello {0} {1} {2}', 'Mona', 'the', 'Octocat')\n```\n\n返回“Hello Mona the Octocat”。\n\n#### 逸出括号示例\n\n```javascript\nformat('{{Hello {0} {1} {2}!}}', 'Mona', 'the', 'Octocat')\n```\n\n返回“{Hello Mona the Octocat!}”。\n\n### 加入\n\n`join( array, optionalSeparator )`\n\n`array` 的值可以是数组，也可以是字符串。\n`array` 中的所有值都连接成一个字符串。 如果提供 `optionalSeparator`，则它将插入到连接的值之间， 否则使用默认分隔符 `,`。 抛出值到字符串。\n\n#### `join` 的示例\n\n`join(github.event.issue.labels.*.name, ', ')` 可能返回“bug, help wanted”\n\n### toJSON\n\n`toJSON(value)`\n\n对 `value` 返回适合打印的 JSON 表示形式。 你可以使用此函数调试上下文中提供的信息。\n\n#### `toJSON` 的示例\n\n`toJSON(job)` 可能返回 `{ \"status\": \"success\" }`\n\n### fromJSON\n\n`fromJSON(value)`\n\n返回 `value` 的 JSON 对象或 JSON 数据类型。 可以使用此函数将 JSON 对象作为计算表达式提供，或使用此函数转换可以 JSON 或 JavaScript 表示的任何数据类型，例如字符串、布尔值、null 值、数组和对象。\n\n#### 返回 JSON 对象的示例\n\n此工作流在一个作业中设置 JSON 矩阵，并使用输出和 `fromJSON` 将其传递给下一个作业。\n\n```yaml copy\nname: build\non: push\njobs:\n  job1:\n    runs-on: ubuntu-latest\n    outputs:\n      matrix: ${{ steps.set-matrix.outputs.matrix }}\n    steps:\n      - id: set-matrix\n        run: echo \"matrix={\\\"include\\\":[{\\\"project\\\":\\\"foo\\\",\\\"config\\\":\\\"Debug\\\"},{\\\"project\\\":\\\"bar\\\",\\\"config\\\":\\\"Release\\\"}]}\" >> $GITHUB_OUTPUT\n  job2:\n    needs: job1\n    runs-on: ubuntu-latest\n    strategy:\n      matrix: ${{ fromJSON(needs.job1.outputs.matrix) }}\n    steps:\n      - run: echo \"Matrix - Project ${{ matrix.project }}, Config ${{ matrix.config }}\"\n```\n\n#### 返回 JSON 数据类型的示例\n\n此工作流使用 `fromJSON` 将环境变量从字符串转换为布尔值或整数。\n\n```yaml copy\nname: print\non: push\nenv:\n  continue: true\n  time: 3\njobs:\n  job1:\n    runs-on: ubuntu-latest\n    steps:\n      - continue-on-error: ${{ fromJSON(env.continue) }}\n        timeout-minutes: ${{ fromJSON(env.time) }}\n        run: echo ...\n```\n\n工作流使用 `fromJSON()` 函数将环境变量 `continue` 从字符串转换为布尔值，从而允许其决定是否在出错时继续。 同样，它将 `time` 环境变量从字符串转换为整数，以分钟为单位设置作业的超时值。\n\n### hashFiles\n\n`hashFiles(path)`\n\n返回与 `path` 模式匹配的文件集的单个哈希。 可以提供用逗号分隔的单个 `path` 模式或多个 `path` 模式。\n`path` 与 `GITHUB_WORKSPACE` 目录相关，且仅包含 `GITHUB_WORKSPACE` 内的文件。 此函数为每个匹配的文件计算单独的 SHA-256 哈希， 然后使用这些哈希来计算文件集的最终 SHA-256 哈希。 如果 `path` 模式与任何文件都不匹配，则返回空字符串。 有关 SHA-256 的更多信息，请参阅 [SHA-2](https://en.wikipedia.org/wiki/SHA-2)。\n\n你可以使用模式匹配字符来匹配文件名。 与 `hashFiles` 匹配的模式遵循 glob 模式匹配，并且在 Windows 上不区分大小写。 有关支持的模式匹配字符的详细信息，请参阅 [](https://www.npmjs.com/package/@actions/glob#patterns) 文档中的`@actions/glob`部分。\n\n#### 单个模式示例\n\n匹配存储库中的任何 `package-lock.json` 文件。\n\n`hashFiles('**/package-lock.json')`\n\n匹配根级别 `.js` 目录中的所有 `src` 文件，但忽略 `src` 的任何子目录。\n\n`hashFiles('/src/*.js')`\n\n匹配根级别 `.rb` 目录中的所有 `lib` 文件，包括 `lib` 的任何子目录。\n\n`hashFiles('/lib/**/*.rb')`\n\n#### 多个模式示例\n\n为存储库中的任何 `package-lock.json` 和 `Gemfile.lock` 文件创建哈希。\n\n`hashFiles('**/package-lock.json', '**/Gemfile.lock')`\n\n为根级别 `.rb` 目录中的所有 `lib` 文件（包括 `lib` 的任何子目录）创建哈希，但排除 `.rb` 子目录中的 `foo` 文件。\n\n`hashFiles('/lib/**/*.rb', '!/lib/foo/*.rb')`\n\n### 大小写\n\n`case( pred1, val1, pred2, val2, ..., default )`\n\n按顺序计算谓词，并返回与计算结果为 `true`的第一个谓词对应的值。 如果没有谓词匹配，则返回最后一个参数作为默认值。\n\n#### 单个谓词的示例\n\n```yaml\nenv:\n  MY_ENV_VAR: ${{ case(github.ref == 'refs/heads/main', 'production', 'development') }}\n```\n\n当 ref 为 `MY_ENV_VAR` 时，设置 `production` 为 `refs/heads/main`；否则，将其设置为 `development`。\n\n#### 具有多个谓词的示例\n\n```yaml\nenv:\n  MY_ENV_VAR: |-\n    ${{ case(\n      github.ref == 'refs/heads/main', 'production',\n      github.ref == 'refs/heads/staging', 'staging',\n      startsWith(github.ref, 'refs/heads/feature/'), 'development',\n      'unknown'\n    ) }}\n```\n\n根据分支设置 `MY_ENV_VAR`：`production` 表示 `main`，`staging` 表示 `staging`，`development` 表示以 `feature/` 开头的分支，或 `unknown` 表示所有其他分支。\n\n## 状态检查函数\n\n可以将以下状态检查函数用作 `if` 条件中的表达式。 除非包含这些函数之一，否则将应用 `success()` 的默认状态检查。 有关 `if` 条件的详细信息，请参阅“[GitHub Actions 的工作流语法](/zh/actions/reference/workflows-and-actions/workflow-syntax#jobsjob_idif)”和“[元数据语法参考](/zh/actions/reference/workflows-and-actions/metadata-syntax#runsstepsif)”。\n\n在 `if` 条件之外，可以使用 `job.status` 来访问作业状态。 有关详细信息，请参阅“[上下文参考](/zh/actions/reference/workflows-and-actions/contexts#job-context)”。\n\n### success\n\n当前面的所有步骤都成功时返回 `true`。\n\n#### `success` 的示例\n\n```yaml\nsteps:\n  ...\n  - name: The job has succeeded\n    if: ${{ success() }}\n```\n\n### 始终\n\n导致步骤始终执行，并返回 `true`，即使取消也一样。\n`always` 表达式最适用于步骤级别或预期即使作业取消仍会运行的任务。 例如，即使作业取消，仍然可以使用 `always` 发送日志。\n\n> \\[!WARNING]\n> 避免将 `always` 用于任何可能出现严重故障的任务，例如：获取源代码，否则工作流可能会挂起直到超时。如果要无论作业或步骤成功与否都运行它，请使用推荐的替代方案：`if: ${{ !cancelled() }}`\n\n#### `always` 的示例\n\n```yaml\nif: ${{ always() }}\n```\n\n### cancelled\n\n如果工作流被取消，则返回 `true`。\n\n#### `cancelled` 的示例\n\n```yaml\nif: ${{ cancelled() }}\n```\n\n### 失败\n\n如果作业的任何先前步骤失败，将返回 `true`。 如果有一系列依赖项作业，则 `failure()` 在任何上级作业失败时返回 `true`。\n\n#### `failure` 的示例\n\n```yaml\nsteps:\n  ...\n  - name: The job has failed\n    if: ${{ failure() }}\n```\n\n#### 有条件的失败\n\n可以包含一个在失败后运行的步骤的额外条件，但仍必须包含 `failure()` 以覆盖自动应用于不包含状态检查函数的 `success()` 条件的默认 `if` 状态检查。\n\n##### 有条件 `failure` 的示例\n\n```yaml\nsteps:\n  ...\n  - name: Failing step\n    id: demo\n    run: exit 1\n  - name: The demo step has failed\n    if: ${{ failure() && steps.demo.conclusion == 'failure' }}\n```\n\n## 对象筛选器\n\n可使用 `*` 语法来应用筛选器并选择集合中的匹配项。\n\n例如，考虑名为 `fruits` 的对象数组。\n\n```json\n[\n  { \"name\": \"apple\", \"quantity\": 1 },\n  { \"name\": \"orange\", \"quantity\": 2 },\n  { \"name\": \"pear\", \"quantity\": 1 }\n]\n```\n\n筛选器 `fruits.*.name` 返回数组 `[ \"apple\", \"orange\", \"pear\" ]`。\n\n还可以对某个对象使用 `*` 语法。 例如，假设有一个名为 `vegetables` 的对象。\n\n```json\n\n{\n  \"scallions\":\n  {\n    \"colors\": [\"green\", \"white\", \"red\"],\n    \"ediblePortions\": [\"roots\", \"stalks\"],\n  },\n  \"beets\":\n  {\n    \"colors\": [\"purple\", \"red\", \"gold\", \"white\", \"pink\"],\n    \"ediblePortions\": [\"roots\", \"stems\", \"leaves\"],\n  },\n  \"artichokes\":\n  {\n    \"colors\": [\"green\", \"purple\", \"red\", \"black\"],\n    \"ediblePortions\": [\"hearts\", \"stems\", \"leaves\"],\n  },\n}\n```\n\n筛选器 `vegetables.*.ediblePortions` 的计算结果如下：\n\n```json\n\n[\n  [\"roots\", \"stalks\"],\n  [\"hearts\", \"stems\", \"leaves\"],\n  [\"roots\", \"stems\", \"leaves\"],\n]\n```\n\n由于对象不保留顺序，因此无法保证输出的顺序。"}