Linux Shell | set、env、export 用法区别

发布于:2025-09-09 ⋅ 阅读:(14) ⋅ 点赞:(0)

注:本文为 “Linux Shell | 环境变量设置命令” 相关合辑。

英文引文,机翻未校。
中文引文,未全整理去重。
如有内容异常,请看原文。


What is the difference between env, setenv, export and when to use?

env、setenv、export 的区别是什么,何时该用哪一个?

Recently I noticed we have 3 options to set environment variables:
最近我注意到有三种方式来设置环境变量:

  1. export envVar1=1
  2. setenv envVar2 2
  3. env envVar3=3

If there are any other ways, please enlighten us.
若有其他方式,请指教。

When should I prefer one over the other? Please suggest guidelines.
应该在什么场景下优先使用哪一种?请给出指导原则。

As for shell compatibility, which is the most expansive (covers more shell dialects)?
就 shell 兼容性而言,哪一种方式支持最广(涵盖更多 shell 方言)?

I already noticed this answer but I wish to expand the question with env and usage preference guidelines.
我已注意到这个回答,但希望把 env 及使用偏好也一并扩展进来。

edited Feb 17 at 10:06
asked Jun 3, 2017 at 6:48
Maroshi

Answers

export VARIABLE_NAME='some value' is the way to set an environment variable in any POSIX-compliant shell (sh, dash, bash, ksh, etc.; also zsh).
export VARIABLE_NAME='some value' 是在任何符合 POSIX 的 shell(shdashbashksh 等,以及 zsh)中设置环境变量的方式。

If the variable already has a value, you can use export VARIABLE_NAME to make it an environment variable without changing its value.
若该变量已有值,可直接使用 export VARIABLE_NAME 将其提升为环境变量,而不改变其值。

Pre-POSIX Bourne shells did not support this, which is why you’ll see scripts that avoid export VARIABLE_NAME='some value' and use VARIABLE_NAME='some value'; export VARIABLE_NAME instead.
早期的 POSIX 前 Bourne shell 不支持这种写法,因此你会看到一些脚本避免使用 export VARIABLE_NAME='some value',而写成 VARIABLE_NAME='some value'; export VARIABLE_NAME

But pre-POSIX Bourne shells are extremely rare nowadays.
但如今 POSIX 前 Bourne shell 已极为罕见。

setenv VARIABLE_NAME 'some value' is the csh syntax to set an environment variable.
setenv VARIABLE_NAME 'some value' 是 csh 语法中设置环境变量的方式。

setenv does not exist in sh, and csh is extremely rarely used in scripts and has been surpassed by bash for interactive use for the last 20 years (and zsh for even longer), so you can forget about it unless you encounter it.
setenv 在 sh 中不存在;csh 极少用于脚本,且交互使用上也早已被 bash(乃至更早就被 zsh)取代,因此除非遇到,大可忽略。

The env command is very rarely useful except in shebang lines.
env 命令除了用在 shebang 行外极少有用。

When invoked without arguments, it displays the environment, but export does it better (sorted, and often quoted to disambiguate newlines in values from newlines that separate values).
无参数调用时,它会显示环境,但 export 做得更好(已排序,且通常加引号以区分值中的换行与分隔换行)。

When invoked with arguments, it runs a command with extra environment variables, but the same command without env also works (VAR=value mycommand runs mycommand with VAR set to value, just like env VAR=value mycommand).
带参数调用时,它会以额外环境变量运行一条命令,但不写 env 也一样可行(VAR=value mycommandenv VAR=value mycommand 效果相同)。

The reason env is useful in shebang line is that it performs PATH lookup, and it happens to not do anything else when invoked with a command name.
之所以 shebang 行要用 env,是因为它会做 PATH 查找,且在指定命令名时恰好不做多余动作。

The env command can be useful to run a command with only a few environment variables with -i, or without parameters to display the environment including variables with invalid names that the shell doesn’t import.
env 也适合用 -i 运行命令时只保留少量环境变量,或无参数时显示环境(包括 shell 不导入的非法变量名)。

edited May 8, 2024 at 15:41
answered Jun 3, 2017 at 23:46
Gilles ‘SO- stop being evil’

env is very useful if you need to run a command with e.g. sudo and at the same time set an environment variable: sudo env var=value thecommand.
env 在你需要用 sudo 运行命令并同时设置环境变量时非常有用:sudo env var=value thecommand

The sudo command, depending on its setup, clears the environment, and sudo var=value thecommand is not valid, as it would try to run var=value as a command.
sudo 根据其配置可能清空环境,而 sudo var=value thecommand 是无效的,因为它会把 var=value 当成命令去执行。
– Kusalananda

Commented Feb 17 at 12:14

@Kusalananda sudo VAR=value thecommand hasn’t always worked, but it was added 10 years before I posted this answer.
@Kusalananda sudo VAR=value thecommand 并非一直有效,但在我回答之前 10 年就已加入。
– Gilles ‘SO- stop being evil’
Commented Feb 17 at 12:47

Well, using env would make it also work with e.g. doas and similar commands.
env 还能让命令在 doas 等类似工具中同样有效。
– Kusalananda
Commented Feb 17 at 14:05

Setting a variable like VAR='asdf' leaves environment unmodified, meaning that the programs you launch in the same session will know nothing about VAR and will be unable to access it.
VAR='asdf' 这样设置变量不会改变环境,意味着你在同一会话中启动的程序对此一无所知,也无法访问它。

You want this behaviour when writing shell scripts.
编写 shell 脚本时正需要这种行为。

export, on the other hand, is a bash builtin that modifies the environment thus making the exported variable visible for child processes spawned in the current session.
export 是 bash 的内建命令,会修改环境,使导出变量对当前会话产生的子进程可见。

You can achieve the same by running VAR='asdf' %program_name%.
你也可以通过 VAR='asdf' %program_name% 达到同样效果。

env is not a builtin, but a program by itself.
env 不是内建命令,而是一个独立程序。

On the surface it works exactly like when you VAR='asdf' %program_name%, but at the lower level things get a little more complicated.
表面上它与 VAR='asdf' %program_name% 行为一致,但底层稍微复杂。

First, the env gets launched. It modifies environment, then executes the command with given arguments.
首先,env 被启动,它修改环境后,再执行给定参数的命令。

The same behaviour you can acheive in your own code by using exec(3) system call.
在自己的代码里,可通过 exec(3) 系统调用实现同样行为。

setenv is just export in csh-family shells, as stated in your answer.
setenv 就是 csh 家族 shell 里的 export,正如你的回答所说。

answered Jun 3, 2017 at 7:06
user230253

In modern shells, VAR=asdf does update the environment if VAR was already in the environment.
在现代 shell 中,若 VAR 原本就在环境中,则 VAR=asdf 会更新环境。
(This wasn’t true in the original Bourne shell.)
(在最初的 Bourne shell 中并非如此。)
– Gilles ‘SO- stop being evil’
Commented Jun 3, 2017 at 22:32


Difference between (bash) shell variables which are exported and those which are not

已导出与未导出的 (bash) shell 变量之间的区别

Bash seems to differentiate between variables which are exported and those which are not.
Bash 似乎会区分已导出的变量与未导出的变量。

example:
示例:

$ FOO=BAR
$ set | grep FOO
FOO=BAR
$ env | grep FOO

set sees the variable but env does not.
set 能查看到变量,而 env 却看不到。

$ export BAR=FOO
$ set | grep FOO
BAR=FOO
FOO=BAR
$ env | grep FOO
BAR=FOO

set sees both variables but env sees only the exported variable.
set 能看到两个变量,而 env 只能看到已导出的那个。

I know that set is a bash builtin and env is not.
我知道 set 是 bash 的内建命令,而 env 不是。

What are the differences between variables which are exported and those which are not?
已导出与未导出的变量到底有什么区别?

edited May 21 at 9:44
asked Oct 25, 2010 at 22:15
Lesmana

Terminology note: an “environment variable” is always exported. A non-exported variable is a “shell variable” (or “parameter”).
术语提示:“环境变量” 总是已导出的;未导出的变量被称为 “shell 变量” 或 “参数”。
– Gilles ‘SO- stop being evil’
Commented Sep 13, 2012 at 0:28

Answer

Exported variables are carried into the environment of commands executed by the shell that exported them, while non-exported variables are local to the current shell invocation.
已导出变量会被带入由导出它们的 shell 执行的命令的环境中,而未导出变量仅对当前 shell 实例有效。

From the export man page:
摘自 export 手册页:

The shell shall give the export attribute to the variables corresponding to the specified names, which shall cause them to be in the environment of subsequently executed commands.
shell 将为指定名称的变量赋予导出属性,使这些变量出现在随后执行的命令的环境中。

set outputs the current environment, which includes any local non-exported variables.
set 输出当前环境,其中包含所有本地(未导出)变量。

env is used to launch programs in a new environment, and with no arguments will output what that new environment would be.
env 用于在一个新环境中启动程序;无参数时,它会输出该新环境将包含的内容。

Since env is creating a new environment, only exported variables are brought through, as is the case for any program launched from that shell.
由于 env 会创建一个新的环境,只有已导出变量才会被传递过去,从该 shell 启动的任何程序也是如此。

For example, spawning a second shell within the first (I used $$ to represent prompts in the inner shell):
例如,在第一个 shell 中再启动一个子 shell(我用 $$ 表示子 shell 的提示符):

$ FOO=BAR
$ bash
$$ echo $FOO             # Note the empty line

$$ exit
$ export FOO
$ bash
$$ echo $FOO
BAR
$$

Note that it’s the variable that’s exported, not just its value.
请注意,导出的是变量本身,而不仅仅是它的值。

This means that once you export FOO, FOO becomes a global variable and shows up in subsequent environments, even if changed later:
这意味着一旦执行了 export FOOFOO 就成了全局变量,即使后续再修改它,也会出现在之后的环境中:

$ export FOO
$ FOO=BAR
$ bash
$$ echo $FOO
BAR
$$

edited Feb 19, 2019 at 16:20
Stéphane Chazelas
answered Oct 25, 2010 at 22:25
Michael Mrozek

so if you’re only concerned about the current shell, do you need to export? Separately, why would locale for the current shell not show the updates?
因此,如果你只关心当前 shell,是否还需要导出?另外,为什么当前 shell 的 locale 不会显示更新?
– Pacerier
Commented May 29, 2019 at 10:25


Shell 环境变量及相关命令全解析

一、环境变量的核心概念与分类

1.1 变量的本质与作用

环境变量是 Linux 系统中用于存储系统状态、用户配置等信息的键值对,用于控制程序运行环境。根据作用范围和继承特性,可分为:

  • shell 变量:仅在当前 shell 进程中有效,包含 shell 私有变量(如 bash 特有的 BASHBASHOPTS)和用户自定义变量,不被子进程继承。
  • 环境变量:可被当前 shell 的所有子进程(及孙进程)继承,与具体 shell 无关(如 HOMEPATH),具有“传子不传父”的特性。

1.2 核心命令(set、env、export)的核心区别

命令 显示范围 可操作对象 继承性特点
set 所有 shell 变量(含环境变量+私有变量) 显示/设置 shell 变量,修改 shell 特性 私有变量不可继承,环境变量可继承
env 仅环境变量 显示/设置环境变量,管理进程环境 可被子进程继承
export 仅已导出为环境变量的 shell 变量 将 shell 变量导出为环境变量 导出后可被子进程继承

二、核心命令的详细用法与示例

2.1 set 命令:管理 shell 变量与特性

  • 基础功能:显示当前 shell 中所有变量(包括环境变量和私有变量)。

    $ set | grep "HOME"  # 查看包含 HOME 的变量
    
  • 扩展选项

    • -a:标记后续修改的变量,自动导出为环境变量(等价于 export);
    • -u:使用未定义变量时显示错误;
    • -x:执行命令前打印命令及参数(调试脚本常用)。
    $ set -a  # 开启自动导出
    $ var=123  # 自动成为环境变量
    $ set +a  # 关闭自动导出
    
    $ set -x  # 开启调试模式
    $ echo "test"  # 输出 + echo test 及 test
    

2.2 env 命令:管理环境变量与进程环境

  • 基础功能:显示当前用户的环境变量。

    $ env | grep "PATH"  # 查看 PATH 环境变量
    
  • 特殊用法

    • -i:启动全新空环境的进程(不继承当前环境变量);
    • -u:临时移除指定环境变量后执行命令。
    $ env -i bash  # 启动无环境变量的新 shell
    $ env -u PATH ls  # 执行 ls 时临时移除 PATH 变量(需指定绝对路径)
    

2.3 export 命令:导出变量为环境变量

  • 基础功能:将 shell 变量导出为环境变量,或显示已导出的环境变量。

    $ var=hello  # 定义 shell 变量
    $ export var  # 导出为环境变量
    $ env | grep "var"  # 输出 var=hello
    
  • 选项说明

    • -f:导出函数(供子进程使用);
    • -n:从环境变量中移除指定变量(保留为 shell 变量);
    • -p:列出所有导出的环境变量(同无参数 export)。
    $ export -n var  # 从环境变量中移除 var,保留 shell 中的 var
    $ export -f my_func  # 导出函数 my_func 到子进程
    

三、其他变量操作命令(unset、readonly、declare)

3.1 unset:清除变量

用于删除 shell 变量或环境变量(不可删除只读变量)。

$ export test=123
$ unset test  # 清除变量 test

3.2 readonly:设置只读变量

将变量设为只读,禁止修改或删除。

$ export test=123
$ readonly test  # 设为只读
$ test=456  # 报错:-bash: test: readonly variable
$ unset test  # 报错:cannot unset: readonly variable

3.3 declare:声明与管理变量(同 typeset)

选项 说明
-x 导出为环境变量(等价于 export
-r 设为只读(等价于 readonly
-i 指定为整数类型
-a 声明数组变量
-f 仅显示函数

示例:

$ declare -i num=10  # 声明整数变量
$ num="20abc"  # 自动转换为 20
$ echo $num  # 输出 20

$ declare -a arr=("a" "b")  # 声明数组
$ echo ${arr[1]}  # 输出 b

四、环境变量的生效与配置文件

4.1 变量的生命周期

  • 临时变量:通过 export 直接定义,关闭 shell 后失效。
  • 永久变量:需写入配置文件,按作用范围分为:
配置文件 作用范围 生效时机 生效方式(修改后)
/etc/profile 所有用户(系统级) 用户登录时 source /etc/profile
~/.bash_profile 当前用户 用户登录时 source ~/.bash_profile
~/.bashrc 当前用户 启动新 shell 时 source ~/.bashrc
~/.bash_logout 当前用户 用户退出登录时 无需额外操作

4.2 bash 初始化加载顺序

  1. 读取 /etc/profile
  2. 依次读取 ~/.bash_profile~/.bash_login~/.profile(存在即停止)。

五、变量作用域与继承特性

5.1 作用域分类

  • 局部变量:仅在函数内部有效,需用 local 声明。

    $ func() { local var=123; echo $var; }
    $ func  # 输出 123
    $ echo $var  # 无输出(局部变量)
    
  • 全局变量:在当前 shell 进程中有效,默认定义的变量即为全局变量,不被子进程继承。

  • 环境变量:通过 export 导出的全局变量,可被所有子进程继承。

5.2 继承示例

# 父 shell 定义变量
$ var1=local  # 未导出(全局变量)
$ export var2=env  # 环境变量

# 进入子 shell
$ bash

# 子 shell 中查看
$ echo $var1  # 无输出(未继承)
$ echo $var2  # 输出 env(已继承)

# 退出子 shell
$ exit

六、跨 shell 差异与 setenv 命令

6.1 不同 shell 的变量命令差异

shell 类型 定义环境变量的命令 语法格式示例
bash/sh export export PATH="$PATH:/new/dir"
csh/tcsh setenv setenv PATH "$PATH:/new/dir"
zsh 兼容 export,支持部分 csh 特性 同 bash 或 csh 语法

6.2 setenv 与 export 的核心区别

  • 适用 shellsetenv 属于 csh/tcsh,export 属于 bash/sh。
  • 语法setenv 变量名 值(无等号),export 变量名=值(有等号)。

七、环境变量的高级操作

7.1 批量管理变量

  • 从文件加载变量:将变量定义在文件中(如 env.sh),通过 source 加载。
    # env.sh 内容
    export APP=/usr/app
    export PATH=$APP/bin:$PATH
    
    $ source env.sh  # 加载变量(当前 shell 生效)
    

7.2 导出函数到子进程

通过 export -f 将函数变为环境函数,供子进程使用。

$ my_func() { echo "Hello"; }
$ export -f my_func  # 导出函数
$ bash -c 'my_func'  # 子进程执行,输出 Hello

八、调试与问题解决

8.1 查看变量来源

搜索配置文件定位变量定义:

$ grep "export PATH" ~/.bashrc ~/.bash_profile /etc/profile

8.2 验证变量继承

通过子 shell 检查环境变量是否被继承:

$ export TEST=123
$ bash -c 'echo $TEST'  # 输出 123 说明继承成功

8.3 误删 PATH 变量的恢复

临时恢复命令:

$ export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

永久恢复需修改配置文件(如 ~/.bashrc)添加上述内容。

九、常见环境变量及其作用

变量名 作用描述
PATH shell 查找可执行程序的目录列表(冒号分隔)
HOME 当前用户的主目录路径
SHELL 当前使用的 shell 类型(如 /bin/bash
HISTSIZE 保存历史命令的条数
LANG 语言与字符编码设置
PS1 命令提示符(root 为 #,普通用户为 $
LD_LIBRARY_PATH 动态链接器查找库文件的路径

环境变量继承关系


Shell 环境变量手册

适用于 bash/zsh/csh

1 变量分类与生命周期

类型 可见范围 生命周期 创建/销毁方式
shell 变量 仅当前 shell 随 shell 终止 var=val / unset var
环境变量 当前 shell + 全部子进程 随 shell 终止(或持久化) export var=val / unset var
只读变量 同 shell 变量 随 shell 终止 readonly var=val
空环境 无继承 手动创建 env -i

2 核心命令速查表

命令 主要用途 典型选项 备注
set 查看/修改 所有 变量 -a 自动导出;-u 未定义报错;-x 调试跟踪 私有变量也在结果里
env 查看/设置 环境变量 -i 空环境;-u VAR 临时移除变量 仅显示可继承变量
export 把 shell 变量提升为环境变量 -n 取消导出;-f 导出函数;-p 列表 无参时等价于 export -p
unset 删除 shell/环境变量 只读变量不可删
readonly 设为只读 仅当前 shell 生效
declare / typeset 声明变量属性 -x 导出;-r 只读;-i 整数;-a/-A 数组 功能与 export/readonly 重叠

3 跨 Shell 语法差异(速记)

Shell 家族 设置环境变量 读取 示例
bash/zsh export VAR=val $VAR export PATH=$PATH:/opt/bin
csh/tcsh setenv VAR val $VAR setenv PATH "$PATH:/opt/bin"

4 配置与持久化

  1. 仅当前用户~/.bashrc~/.zshrc
  2. 所有用户/etc/profile/etc/bash.bashrc
  3. 立即生效source <file>. <file>

加载顺序(bash 为例):
/etc/profile~/.bash_profile~/.bash_login~/.profile~/.bashrc

5 调试与排查

场景 命令
查变量定义位置 grep -R "export VAR" /etc ~/.bash*
确认已导出 `export -p
验证继承 父 shell:export VAR=valbashecho $VAR
快速清空环境 env -i bash
临时移除变量 env -u VAR command

6 常用示例

  1. 临时扩展 PATH

    export PATH=$PATH:$HOME/custom_bin
    
  2. 批量自动导出

    set -a
    APP_HOME=/opt/app
    APP_LOG=/var/log/app
    set +a          # 之后 APP_HOME/APP_LOG 自动成为环境变量
    
  3. 函数导出给子进程

    hello() { echo "hi $1"; }
    export -f hello
    bash -c 'hello world'   # 子 shell 可直接调用
    
  4. 只读保护

    declare -r CONFIG=/etc/app.conf
    unset CONFIG            # 报错:cannot unset
    
  5. 恢复误删 PATH

    export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
    

7 特殊字符与引号

需求 写法
含空格 export MSG='Hello World'
含变量 export PATH="$HOME/bin:$PATH"
含单引号 export NOTE='It'\''s fine'

8 数组与整数声明

declare -i num=10     # 整数
declare -a arr=(a b c)
declare -A map=([k1]=v1 [k2]=v2)

9 一键速查脚本(复制即用)

# 查看所有环境变量来源
grep -RHn "^export " /etc/profile /etc/bash.bashrc ~/.bash* 2>/dev/null

# 查看当前 shell 变量 vs 环境变量
echo "=== ALL VARIABLES ==="; set | sort
echo "=== ENV VARIABLES ==="; env | sort
echo "=== EXPORTED ========="; export -p | sort

via:


网站公告

今日签到

点亮在社区的每一天
去签到