为何子shell执行命令的输出无需source即可显示在主shell?
关于Shell脚本输出与子Shell的疑惑解答
这是个非常常见的误解,我来给你把逻辑理清楚~
首先得明确两个执行方式的核心差异:
- 用
./foo.sh执行时,系统确实会启动一个子Shell进程来运行脚本里的命令; - 用
source ./foo.sh执行时,脚本里的命令会直接在当前Shell进程中运行,不会创建子进程。
但你疑惑的「为什么子Shell的输出能在主终端看到」,关键点在于标准输出(stdout)的继承关系:
当你在终端里启动子Shell时,子Shell会默认继承父Shell(也就是你的主终端)的标准输出、标准错误流。所以子Shell里的 echo "Hello World" 会把内容输出到它自己的stdout,而这个stdout和主终端是连通的,自然就能直接看到输出结果。
那 source 和直接执行脚本的真正区别到底在哪里?其实不在输出,而在对Shell环境状态的修改:
- 如果脚本里有修改环境变量、切换当前目录、定义别名这类操作,用
./foo.sh执行的话,这些修改只会作用于子Shell进程,子Shell运行结束后,主Shell的环境不会有任何变化; - 但用
source执行的话,所有修改都会直接作用于当前Shell进程,执行完后这些变化会保留在主Shell里。
举个实际例子更直观:
写一个测试脚本 test_env.sh:
echo "This is output from the script" export MY_ENV_VAR="I'm only here if you source me" cd /tmp
- 用
./test_env.sh执行:你会看到输出,但执行完后在主Shell里跑echo $MY_ENV_VAR会得到空值,pwd也还是原来的目录; - 用
source ./test_env.sh执行:同样能看到输出,而且echo $MY_ENV_VAR会显示定义的值,pwd会显示/tmp。
简单总结:输出能不能到终端,和是不是子Shell无关——只要stdout没被重定向,不管子Shell还是当前Shell,都会把内容送到终端;而 source 的作用是让脚本修改当前Shell的环境,不是为了让输出显示出来~
内容的提问来源于stack exchange,提问作者Danny Rogers
相关产品推荐
相关产品推荐

