> For the complete documentation index, see [llms.txt](https://man.bsdcn.org/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://man.bsdcn.org/man1/env.1.md).

# env(1)

`env` — 设置环境并执行命令，或打印环境

## 名称

`env`

## 概要

`env [-0iv] [-L | -U user[/class]] [-u name] [name=value ...]`

`env [-iv] [-C altwd] [-L | -U user[/class]] [-P altpath] [-S string] [-u name] [name=value ...] utility [argument ...]`

## 描述

`env` 实用程序在按命令行指定修改环境后执行另一个 `utility`。每个 `name`=`value` 选项指定环境变量 `name` 的设置，值为 `value`。所有此类环境变量都在执行 `utility` 之前设置。

选项如下：

**`-0`** 每行输出以 NUL 结尾，而非换行。

**`-i`** 仅使用由 `name`=`value` 选项指定的环境变量执行 `utility`。`env` 继承的环境被完全忽略。

**`-C`** `altwd` 在执行指定的 `utility` 程序之前切换到指定的备用工作目录。

**`-L | -U`** `user`\[/`class`] 在处理任何 `-i` 或 `-u` 选项之后、处理任何 `name`=`value` 选项之前，将指定用户和登录类的 login.conf(5) 中的环境变量定义添加到环境中。如果使用 `-L`，仅读取系统范围的 **`/etc/login.conf.db`** 文件；如果使用 `-U`，还会读取指定用户的 **`~/.login_conf`**。用户可以按名称或 uid 指定。如果给定的用户名为“`-`”，则不进行用户查找，登录类默认为“`default`”（如果未显式给出），并且不对值进行任何替换。

**`-P`** `altpath` 搜索由 `altpath` 指定的目录集合来定位指定的 `utility` 程序，而不是使用 `PATH` 环境变量的值。

**`-S`** `string` 将给定的 `string` 拆分为多个字符串，并将每个结果字符串作为 `env` 实用程序的单独参数处理。`-S` 选项识别一些特殊字符转义序列，还支持环境变量替换，如下所述。

**`-u`** `name` 如果环境变量 `name` 在环境中，则在处理剩余选项之前将其移除。这类似于 [sh(1)](/man1/sh.1.md) 中的 `unset` 命令。`name` 的值不得包含 `=` 字符。

**`-v`** 打印 `env` 实用程序执行的每个处理步骤的详细信息。如果多次指定 `-v`，将打印附加信息。

上述选项仅在任何 `name`=`value` 选项之前指定时才被识别。

如果未指定 `utility`，`env` 打印环境中变量的名称和值。除非指定了 `-0`，每个名称/值对以换行符分隔；指定 `-0` 时，名称/值对以 NUL 分隔。`-0` 和 `utility` 不能同时指定。

`env` 实用程序不处理名称中带有等号（`=`）的 `utility` 值，原因显而易见。这可以通过插入 command(1) 实用程序来轻松解决，该实用程序只是执行其参数；参见下文的实例。

### -S（split-string）处理的细节

`-S` 选项的处理会根据 `string` 中找到的任何空格或 字符将给定的 `string` 拆分为单独的参数。然后，每个新参数被视为如同在原始 `env` 命令上作为单独参数指定一样。

空格和制表符可以通过使用单引号（“`'`”）或双引号（`"`）或反斜杠（`\`）嵌入到其中一个新参数中。单引号会转义所有非单引号字符，直到匹配的单引号。双引号会转义所有非双引号字符，直到匹配的双引号。如果在匹配引号字符之前到达 `string` 末尾，则为错误。

如果 `-S` 会创建一个以 `#` 字符开头的新参数，则该参数和 `string` 的其余部分将被忽略。当你希望新参数以 `#` 字符开头而不导致 `string` 的其余部分被跳过时，可以使用 `\#` 序列。

在处理 `string` 值时，`-S` 处理会将某些字符组合视为表示要采取的操作的转义序列。字符转义序列采用反斜杠表示法。字符及其含义如下：

**`\c`** 忽略 `string` 中的剩余字符。这不得出现在双引号字符串内。

**`\f`** 替换为 <换页> 字符。

**`\n`** 替换为 <换行> 字符。

**`\r`** 替换为 <回车> 字符。

**`\t`** 替换为 <制表符> 字符。

**`\v`** 替换为 <垂直制表符> 字符。

**`\#`** 替换为 `#` 字符。当你需要 `#` 作为通过拆分给定 `string` 创建的某个参数的第一个字符时很有用。

**`\$`** 替换为 `$` 字符。

**`\_`** 如果在双引号字符串内找到，则替换为单个空格。如果在引号字符串外找到，则将其视为原始 `string` 中新参数之间的分隔符。

**`\"`** 替换为 <双引号> 字符。

**`\'`** 替换为 <单引号> 字符。

**`\\`** 替换为反斜杠字符。

<单引号> 和反斜杠的序列是仅在单引号字符串内识别的序列。其他序列在单引号字符串内没有特殊含义。所有转义序列都在双引号字符串内被识别。如果单个 `\` 字符后跟的不是上述列出的字符之一，则为错误。

`-S` 的处理还支持从环境变量中替换值。为此，环境变量的名称必须在 `${}` 内，例如：`${SOMEVAR}`。不支持常见的 shell 语法 `$SOMEVAR`。所有替换的值将是 `env` 实用程序最初调用时环境变量的值。这些值不会被检查上述任何转义序列。并且任何 `name`=`value` 的设置都不会影响 `-S` 处理中用于替换的值。

此外，`-S` 处理不能引用大多数 shell 定义的特殊参数的值。例如，如果 `$*`、`$@`、`$#`、`$?` 或 `$$` 出现在给定的 `string` 内，`-S` 无法识别它们。

### 在 shell 脚本中使用

`env` 实用程序经常用作解释脚本第一行的 `interpreter`，如 execve(2) 中所述。

注意，内核解析解释脚本的 `#!`（第一行）的方式自 FreeBSD 6.0 起已改变。在此之前，FreeBSD 内核会根据该行中找到的任何空白字符（空格或 字符）将该第一行拆分为单独的参数。因此，如果一个名为 **`/usr/local/bin/someport`** 的脚本的第一行为：

```sh
#!/usr/local/bin/php -n -q -dsafe_mode=0
```

那么 **`/usr/local/bin/php`** 程序将以以下参数启动：

```sh
arg[0] = '/usr/local/bin/php'
arg[1] = '-n'
arg[2] = '-q'
arg[3] = '-dsafe_mode=0'
arg[4] = '/usr/local/bin/someport'
```

加上用户执行 `someport` 时指定的任何参数。然而，`#!` 行上的这种多选项处理并非任何其他操作系统解析解释脚本第一行的方式。因此，在 FreeBSD 6.0 版本中做出更改后，该脚本将导致 **`/usr/local/bin/php`** 以以下参数启动：

```sh
arg[0] = '/usr/local/bin/php'
arg[1] = '-n -q -dsafe_mode=0'
arg[2] = '/usr/local/bin/someport'
```

加上用户指定的任何参数。这导致少数脚本的行为发生了重大变化。对于上述脚本，要使其在 FreeBSD 6.0 下的行为与早期版本相同，第一行应更改为：

```sh
#!/usr/bin/env -S /usr/local/bin/php -n -q -dsafe_mode=0
```

`env` 实用程序将以整行作为单个参数启动：

```sh
arg[1] = '-S /usr/local/bin/php -n -q -dsafe_mode=0'
```

然后 `-S` 处理会在执行 **`/usr/local/bin/php`** 之前将该行拆分为单独的参数。

## 环境变量

`env` 实用程序使用 `PATH` 环境变量来定位请求的 `utility`（如果名称不包含 `/` 字符），除非已指定 `-P` 选项。

## 退出状态

`env` 实用程序成功时退出 0，发生错误时退出 >0。

退出状态 126 表示找到了 `utility` 但无法执行。退出状态 127 表示无法找到 `utility`。

## 实例

由于 `env` 实用程序经常用作解释脚本第一行的一部分，以下示例展示了 `env` 实用程序在脚本中的一些有用方式。

解释脚本的内和处理不允许脚本直接将其他脚本作为其自身的解释器引用。作为一种变通方法，以下两者之间的主要区别

```sh
#!/usr/local/bin/foo
```

和

```sh
#!/usr/bin/env /usr/local/bin/foo
```

在于后者即使 **`/usr/local/bin/foo`** 本身是解释脚本也能工作。

`env` 可能最常见的用途是在解释器可能位于不同系统的不同目录中时，为脚本找到正确的解释器。以下示例将通过搜索 `PATH` 指定的目录来找到 `perl` 解释器。

```sh
#!/usr/bin/env perl
```

该示例的一个限制是它假设用户的 `PATH` 值设置为能找到你要执行的解释器。可以使用 `-P` 选项来确保搜索 `utility` 时使用特定的目录列表。注意，此示例还需要 `-S` 选项才能正常工作。

```sh
#!/usr/bin/env -S -P/usr/local/bin:/usr/bin perl
```

上述命令仅在 `perl` 位于 **`/usr/local/bin`** 或 **`/usr/bin`** 中时才找到它。这可以与 `PATH` 的当前值结合，以提供更大的灵活性。注意，`-S` 和 `-P` 选项之间不需要空格：

```sh
#!/usr/bin/env -S-P/usr/local/bin:/usr/bin:${PATH} perl
```

执行名称中带有等号的实用程序：

```sh
env name=value ... command foo=bar arg ...
```

## 兼容性

`env` 实用程序接受 `-` 选项作为 `-i` 的同义词。

## 参见

[printenv(1)](/man1/printenv.1.md), [sh(1)](/man1/sh.1.md), execvp(3), [login.conf(5)](/man5/login.conf.5.md), [environ(7)](/man7/environ.7.md)

## 标准

`env` 实用程序符合 IEEE Std 1003.1-2001 ("POSIX.1")。`-0`、`-C`、`-L`、`-P`、`-S`、`-U`、`-u` 和 `-v` 选项是 FreeBSD 支持的非标准扩展，但在其他操作系统上可能不可用。

## 历史

`env` 命令出现于 4.4BSD。`-P`、`-S` 和 `-v` 选项在 FreeBSD 6.0 中添加。`-0`、`-L` 和 `-U` 选项在 FreeBSD 13.0 中添加。`-C` 选项在 FreeBSD 14.2 中添加。

## 缺陷

`env` 实用程序在处理 `-S` 选项时不考虑多字节字符，这可能导致某些语言环境中的结果不正确。
