# 8.6.用关键词扩展软件包列表

所有关键字也可以带有可选的括号参数。这些参数是所有者、组和模式。该参数用于文件或目录的引用。要更改配置文件的所有者、组和模式，请使用：

```sh
@sample(games,games,640) etc/config.sample
```

这些参数是可选的。如果只需要更改组和模式，请使用：

```sh
@sample(,games,660) etc/config.sample
```

> **警告**
>
> 如果关键字用于 [可选](https://docs.freebsd.org/en/books/porters-handbook/makefiles/#makefile-options) 项目，必须在助手之后添加：`%%FOO%%@sample etc/orbit.conf.sample`。这是因为选项 plist 帮助器用于注释该行，因此它们需要放在前面。有关更多信息，请参见 [`OPTIONS_SUB`](https://docs.freebsd.org/en/books/porters-handbook/makefiles/#options_sub)。

## 8.6.1. `@desktop-file-utils`

安装和卸载后将运行 `update-desktop-database -q`。*永远*不要直接使用，应该在 **Makefile** 中添加 [`USES=desktop-file-utils`](https://docs.freebsd.org/en/books/porters-handbook/uses/#uses-desktop-file-utils)。

## 8.6.2. `@fc` *directory*

为作为参数传递的目录添加一个 `@dir` 条目，并在安装和卸载后运行 `fc-cache -fs` 命令。

## 8.6.3. `@fontsdir` *directory*

为作为参数传递的目录添加一个 `@dir` 条目，并在安装和卸载后运行 `mkfontscale` 和 `mkfontdir` 命令。此外，在卸载时，如果 **fonts.scale** 和 **fonts.dir** 缓存文件为空，还会将其删除。

## 8.6.4. `@info` *file*

将作为参数传递的文件添加到 plist，并在安装和卸载时更新信息文档索引。此外，在卸载时，如果索引为空，还会删除该索引。永远不要手动使用此项，而应该通过 `INFO` 使用。有关更多信息，请参见 [Info Files](https://docs.freebsd.org/en/books/porters-handbook/makefiles/#makefile-info)。

## 8.6.5. `@kld` *directory*

在安装和卸载时对该目录运行 `kldxref`。此外，在卸载时，如果目录为空，还会删除该目录。

## 8.6.6. `@rmtry` *file*

在卸载时删除该文件，如果文件不存在，则不报错。

## 8.6.7. `@sample` *file* \[*file*]

用于通过软件包中捆绑的示例文件处理配置文件的安装。非示例文件（实际文件）是第二个文件名（如果存在），或者是第一个文件名去掉 **.sample** 后缀的版本。

这三件事会发生。首先，将作为参数传递的第一个文件（示例文件）添加到 plist。然后，在安装时，如果找不到实际文件，则将示例文件复制到实际文件。最后，在卸载时，如果实际文件没有被修改，则删除该文件。有关更多信息，请参见 [Configuration Files](https://docs.freebsd.org/en/books/porters-handbook/plist/#plist-config)。

## 8.6.8. `@shared-mime-info` *directory*

在安装和卸载时对该目录运行 `update-mime-database`。

## 8.6.9. `@shell` *file*

将作为参数传递的文件添加到 plist 中。

在安装时，将 *file* 的完整路径添加到 **/etc/shells** 中，同时确保不会重复添加。卸载时，将其从 **/etc/shells** 中移除。

## 8.6.10. `@terminfo`

不要单独使用。如果 Port 安装了 **\*.terminfo** 文件，请在其 **Makefile** 中添加 [`USES=terminfo`](https://docs.freebsd.org/en/books/porters-handbook/uses/#uses-terminfo)。

在安装和卸载时，如果 `tic` 存在，则从 **${PREFIX}/shared/misc** 中的 **\*.terminfo** 文件刷新 **${PREFIX}/shared/misc/terminfo.db**。

## 8.6.11. 基本关键字

有一些硬编码的关键字，并且在 [pkg-create(8)](https://man.freebsd.org/cgi/man.cgi?query=pkg-create\&sektion=8\&format=html) 中有详细文档。为了完整性，本文也会记录这些关键字。

### 8.6.11.1. `@` \[*file*]

空关键字是一个占位符，用于在需要更改文件的所有者、组或模式时使用。例如，要将文件的组设置为 `games` 并添加 setgid 位，请添加：

```sh
@(,games,2755) sbin/daemon
```

### 8.6.11.2. `@preexec` *command*, `@postexec` *command*, `@preunexec` *command*, `@postunexec` *command*

在包安装或卸载过程中执行 *command*。

`@preexec`*command* 在 **pre-install** 脚本中执行 *command*。

`@postexec`*command* 在 **post-install** 脚本中执行 *command*。

`@preunexec`*command* 在 **pre-deinstall** 脚本中执行 *command*。

`@postunexec`*command* 在 **post-deinstall** 脚本中执行 *command*。

如果 *command* 中包含以下任一序列，它们会被内联展开。假设 `@cwd` 被设置为 **/usr/local**，且最后提取的文件是 **bin/emacs**。

`%F`\
展开为最后提取的文件名（如所指定）。在此例中为 **bin/emacs**。

`%D`\
展开为当前目录前缀，如通过 `@cwd` 设置的。在此例中为 **/usr/local**。

`%B`\
展开为完全限定文件名的基本目录部分，即当前目录前缀加上最后的文件路径，去掉尾部文件名。在此例中为 **/usr/local/bin**。

`%f`\
展开为完全限定名称中的文件名部分，或者是 `%B` 的反向操作。在此例中为 **emacs**。

> **重要**
>
> 这些关键字旨在帮助你设置包，以使其尽可能准备好使用。它们 *不得* 被滥用来启动服务、停止服务或运行任何其他修改当前系统的命令。

### 8.6.11.3. `@mode` *mode*

设置所有随后提取文件的默认权限为 *mode*。格式与 [chmod(1)](https://man.freebsd.org/cgi/man.cgi?query=chmod\&sektion=1\&format=html) 使用的格式相同。使用时若不带参数，则设置为默认权限（打包时文件的权限模式）。

> **重要**
>
> 这必须是数字模式，例如 `644`、`4755` 或 `600`。不能是相对模式，例如 `u+s`。

### 8.6.11.4. `@owner` *user*

为所有后续文件设置默认所有者为 *user*。若不带参数，则设置为默认所有者（`root`）。

### 8.6.11.5. `@group` *group*

为所有后续文件设置默认组所有权为 *group*。若不带参数，则设置为默认组所有权（`wheel`）。

### 8.6.11.6. `@comment` *string*

此行在打包时会被忽略。

### 8.6.11.7. `@dir` *directory*

声明目录名称。默认情况下，通过包安装创建的目录会在卸载时自动删除。若需要在 `PREFIX` 下创建一个空目录，或该目录需要有非默认的所有者、组或权限，则使用此项。`PREFIX` 以外的目录需要注册。例如，**/var/db/${PORTNAME}** 需要有一个 `@dir` 条目，而 **${PREFIX}/shared/${PORTNAME}** 如果包含文件或使用默认所有者、组和权限，则不需要。

### 8.6.11.8. `@exec` *command*, `@unexec` *command*（已弃用）

在安装或卸载过程中执行 *command*。请改用 [`@preexec` *command*](https://docs.freebsd.org/en/books/porters-handbook/plist/#plist-keywords-base-exec)。

### 8.6.11.9. `@dirrm` *directory*（已弃用）

声明要在卸载时删除的目录名称。默认情况下，通过包安装创建的目录会在包卸载时被删除。

### 8.6.11.10. `@dirrmtry` *directory*（已弃用）

声明要删除的目录名称，类似于 `@dirrm`，但如果无法删除目录，则不会发出警告。

## 8.6.12. 创建新关键字

通过在 **${PORTSDIR}/Keywords** 目录中定义的关键字，可以扩展包列表文件。每个关键字的设置存储在一个名为 **keyword.ucl** 的 UCL 文件中。该文件必须至少包含以下一个部分：

* `attributes`
* `action`
* `pre-install`
* `post-install`
* `pre-deinstall`
* `post-deinstall`
* `pre-upgrade`
* `post-upgrade`

### 8.6.12.1. `attributes`

更改关键字使用的所有者、组或模式。包含一个关联数组，其中可能的键是 `owner`、`group` 和 `mode`。值分别为用户名、组名和文件模式。例如：

```sh
attributes: { owner: "games", group: "games", mode: 0555 }
```

### 8.6.12.2. `action`

定义关键字的参数会发生什么。包含一个数组，其中可能的值有：

`setprefix`\
设置下一个 plist 条目的前缀。

`dir`\
注册一个在安装时创建并在卸载时删除的目录。

`dirrm`\
注册一个在卸载时删除的目录。已弃用。

`dirrmtry`\
注册一个在卸载时尝试删除的目录。已弃用。

`file`\
注册一个文件。

`setmode`\
设置下一个 plist 条目的模式。

`setowner`\
设置下一个 plist 条目的所有者。

`setgroup`\
设置下一个 plist 条目的组。

`comment`\
不执行任何操作，相当于不输入 `action` 部分。

`ignore_next`\
忽略 plist 中的下一个条目。

### 8.6.12.3. `arguments`

如果设置为 `true`，则添加参数处理，将整个行 `%@` 拆分为编号的参数 `%1`、`%2` 等。例如，对于以下行：

```sh
@foo some.content other.content
```

`%1` 和 `%2` 将分别包含：

```sh
some.content
other.content
```

它还会影响 [`action`](https://docs.freebsd.org/en/books/porters-handbook/plist/#plist-keywords-action) 条目的工作方式。当有多个参数时，必须指定参数的编号。例如：

```sh
actions: [file(1)]
```

### 8.6.12.4. `pre-install`、`post-install`、`pre-deinstall`、`post-deinstall`、`pre-upgrade`、`post-upgrade`

这些关键字包含一个 [sh(1)](https://man.freebsd.org/cgi/man.cgi?query=sh\&sektion=1\&format=html) 脚本，在安装、卸载或升级包之前或之后执行。除了通常的 `@exec %foo` 占位符（如 [`@preexec` *command*](https://docs.freebsd.org/en/books/porters-handbook/plist/#plist-keywords-base-exec) 中描述的）外，还有一个新占位符 `%@`，它表示该关键字的参数。

### 8.6.12.5. 自定义关键字示例

**示例 2. `@dirrmtryecho` 关键字示例**

此关键字执行两项操作：它向打包列表添加一个 `@dirrmtry<span> </span>directory` 行，并在卸载包时回显删除该目录的消息。

```sh
actions: [dirrmtry]
post-deinstall: <<EOD
  echo "Directory %D/%@ removed."
EOD
```

**示例 3. 真实示例，如何实现 `@sample`**

此关键字执行三项操作：它将第一个作为参数传递给 `@sample` 的 *filename* 添加到打包列表中；它将指令添加到 `post-install` 脚本中，以便在目标配置文件不存在时，将示例文件复制到实际配置文件中；它将指令添加到 `post-deinstall` 脚本中，在配置文件未被修改的情况下删除该配置文件。

```sh
actions: [file(1)]
arguments: true
post-install: <<EOD
  case "%1" in
  /*) sample_file="%1" ;;
  *) sample_file="%D/%1" ;;
  esac
  target_file="${sample_file%.sample}"
  set -- %@
  if [ $# -eq 2 ]; then
      target_file=${2}
  fi
  case "${target_file}" in
  /*) target_file="${target_file}" ;;
  *) target_file="%D/${target_file}" ;;
  esac
  if ! [ -f "${target_file}" ]; then
    /bin/cp -p "${sample_file}" "${target_file}" && \
      /bin/chmod u+w "${target_file}"
  fi
EOD
pre-deinstall: <<EOD
  case "%1" in
  /*) sample_file="%1" ;;
  *) sample_file="%D/%1" ;;
  esac
  target_file="${sample_file%.sample}"
  set -- %@
  if [ $# -eq 2 ]; then
      set -- %@
      target_file=${2}
  fi
  case "${target_file}" in
  /*) target_file="${target_file}" ;;
  *) target_file="%D/${target_file}" ;;
  esac
  if cmp -s "${target_file}" "${sample_file}"; then
    rm -f "${target_file}"
  else
    echo "You may need to manually remove ${target_file} if it is no longer needed."
  fi
EOD
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://porters-handbook.bsdcn.org/di-8-zhang-gao-ji-pkgplist-shi-jian/8.6.-yong-guan-jian-ci-kuo-zhan-ruan-jian-bao-lie-biao.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
