什么
set
和命令之间有什么区别env
?什么时候是否应该使用其中一个而不是另一个?
如何它们通常会被调用吗?(典型用途;案例场景)。
答案1
放
set
是shell 内置命令命令。
(由于该问题被标记为 Unix shell,因此我省略了 MS Windows 命令。)
POSIX 规范
内置set
的是POSIX 中定义具有多种功能。
1. 位置参数
内置函数的主要目的set
是
设置或取消设置选项和位置参数。
位置参数由调用程序(通常是(但不一定)是另一个 shell)作为参数传递给 shell(通常是脚本,但可以是交互式的)。第一个参数为$1
,第二个参数为$2
,等等。
该set
命令可以操纵这些参数。每个争论提供给它的设置为位置参数,例如
$ set one two
$ echo "$1"
one
$ echo "$2"
two
set --
取消设置所有位置参数:
$ set --
$ echo $1 # no output
2. 列出 shell 变量
然而,POSIX 规范还描述了其他用途set
:
运行set
本身会打印所有 shell 变量的名称和值。这包括
- 全部shell 变量在当前 shell 中设置并
- 全部环境变量从其父进程继承。
例子:
$ set
HOME='/home/ant'
IFS='
'
LANG='en_US.UTF-8'
LANGUAGE='en_US:en'
PATH='/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin'
PS1='# '
PS2='> '
PS4='+ '
PWD='/home/ant'
在上面的列表中HOME
,LANG
和PATH
是环境变量whileIFS
和PS1
toPS4
都是shell 变量已在当前 shell 中设置。
注意:在 Bash shell 中,set
内置命令还会打印 shell 函数的定义。有关更多信息,请参阅 set 的 Bash 手册。
3. 壳的控制行为
set
还用于控制 shell 的属性,通常(但不一定)是交互式 shell。这是通过运行某些预定义的选项(为了将它们与上面描述的用于设置位置参数的参数区分开来)。
当指定选项时,它们应设置或取消设置 shell 的属性
这些选项的详细信息POSIX 规范. 一个例子是
set -f
该-f
选项禁止当前 shell 执行路径名扩展 (globbing)。此行为也可以使用等效命令配置:
set -o noglob
Bash 等 Shell 会扩展此列表以包含诸如-B
(或-o braceexpand
) 之类的选项;这将启用当前 Shell 中的括号扩展(仅限 Bash 的功能)。
环境
与 不同set
,该env
命令是常规的外部命令,即它不是 shell 的一部分。按照惯例(为了可移植性),在每个 Unix 环境中,该env
程序都是安装到目录中的可执行文件/usr/bin
。
POSIX 规范
该env
工具还由 POSIX 指定。
1. 修改命令的环境
该命令的主要目的env
是运行具有不同/修改的环境的命令。
env [OPTION]... [-] [NAME=VALUE]... [COMMAND [ARG]...]
以下示例git status
使用两个环境变量设置来运行该命令:
env GIT_DIR=~/notes/.git/ GIT_WORK_TREE=~/notes/ git status
-i
with 选项可env
用于运行具有空环境的命令,即,没有从父进程继承任何环境变量。
请注意,如果仅修改一两个环境变量并使用 Bash shell ,则无需这样做,env
因为 Bash 本身已经可以临时修改一个命令的环境。在 Bash 中,上述示例可以简单地运行如下:
GIT_DIR=~/notes/.git/ GIT_WORK_TREE=~/notes/ git status
2.打印环境变量
如果没有提供命令,则会打印当前环境。
$ env
MAIL=/var/mail/root
LANGUAGE=en_US:en
USER=ant
HOME=/home/ant
TERM=xterm
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
LANG=en_US.UTF-8
请注意,这仅打印环境变量 – 而不是诸如PS1
或 之类的shell 变量IFS
。
3. 搜索 PATH 来运行已安装的程序
的另一个用途env
是在 PATH 中搜索命令。
它还可用于运行由 shell 特定命令所遮蔽的外部命令。由于它对 shell 内置命令、关键字、函数或别名(shell 定义的和为 shell 定义的任何东西)一无所知,因此它会在环境变量指定的目录中搜索可执行文件PATH
。
env
在(可能)修改的环境中运行由其第一个参数命名的可执行文件;因此,它不知道或无法使用 shell 内置命令。
例如,此命令将运行 shell 内置版本echo
:
$ echo --version
--version
另一方面,运行echo
将env
执行安装在的程序/usr/bin/echo
:
$ env echo --version
echo (GNU coreutils) 8.15
Copyright (C) 2012 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
4. 脚本
上述行为通常用于可执行脚本的 shebang(第一行),以确保内核使用正确的程序来解释脚本 - 而无需指定解释器程序安装在哪个目录中。
例如,Python 安装在不同系统的不同位置(没有标准位置)。以下 shebang 将导致程序运行脚本python3
- 只要它安装在PATH
环境变量中指定的目录之一中。
#!/usr/bin/env python3
可以在交互式 shell 中通过在命令行中输入以下内容来测试此用法:
$ /usr/bin/env python3 --version
Python 3.2.5
从这个优秀的答案到“/usr/bin/env 如何知道要使用哪个程序?”
内核不想知道诸如这样的环境变量
PATH
。因此 shebang 行上的名称必须是可执行文件的绝对路径。该命令的主要目的
env
是运行具有不同环境的命令,但是因为它在中查找命令名称$PATH
,所以它可以用来向内核提供命令的路径。尽管这并未得到官方保证,但历史上的 Unix 系统提供了
env
,/usr/bin
而现代系统正是由于 的广泛使用才保留了该位置#!/usr/bin/env
。
基本上,使用env
更具可移植性,因为这意味着脚本不需要知道启动命令的首选二进制文件安装在哪里。另请参阅为什么使用“#!/usr/bin/env NAME”而不是“#!/path/to/NAME”作为我的 shebang 更好?