一般情况下,脚本都是在 subshell 中执行,但是相信在修改环境变量、别名等,使它生效时,你也用过诸如: source ./bashrc 等,它就是在当前 shell 执行的一个应用场景。

执行方式

子 shell 中执行

当前 shell 是父进程,生成一个子 shell 进程,在子 shell 中执行脚本。脚本执行完毕,退出子 shell,回到当前 shell。

  1. 作为解释器参数,明确指定解释器

    shell 脚本指定解释器:bash test.shsh test.sh, py 脚本指定 Python 解释器: bash test.py shell 脚本由 shell 解释。如果对于 shell 脚本,你使用 python 解释器,python test.sh 那它就会报错。 这种方式运行的脚本,不需要用 shebang 第一行指定解释器信息,写了也没用。

  2. 作为可执行程序,直接用路径执行

    通过相对路径或者绝对路径执行,无论是 Shell 还是 Python 脚本都需要添加执行权限。chmod +x test.shchmod +x test.py 而在 shell 中执行,它是隐式调用 bash 作为解释器的,如果想要通过这种方式来执行除 shell 以外的,如:python。 perl expect 之类的脚本,就需要 shebang

    注意,一定要写成 ./test.sh,而不是 test.sh,运行其它二进制的程序也一样,直接写 test.sh,linux 系统会去 PATH 里寻找有没有叫 test.sh 的,而只有 /bin, /sbin, /usr/bin,/usr/sbin 等在 PATH 里,你的当前目录通常不在 PATH 里,所以写成 test.sh 是会找不到命令的,要用 ./test.sh 告诉系统说,就在当前目录找。

当前 shell 执行

在当前上下文中执行脚本,不会生成新的进程。脚本执行完毕,回到当前 shell。

脚本中的命令影响到当前 shell,比如下面的例子,当前工作目录受脚本的 cd 影响,切换到了上一级。

1
2
3
4
5
6
7
8
9
10
11
12
# violetv at manjaro in ~/testsh [13:38:47]
$ cat test_subshell.sh
#!/usr/bin/bash
ls
cd ../

# violetv at manjaro in ~/testsh [13:46:25]
$ source test_subshell.sh
1.py ip.txt ping_1.sh ping_condition.sh ping_ipfile.sh ping_sh.sh test test_subshell.sh test.txt

# violetv at manjaro in ~ [13:46:41]
$中输入exit后回车;
  1. 点空格 . ./script.sh

  2. source source script.sh

exec

使用 exec command 方式,会用 command 进程替换当前 shell 进程,并且保持 PID 不变。执行完毕,直接退出,不回到之前的 shell 环境。

参考资料

What is a Subshell?