shell 脚本的三种调用方法以及 bash 如何后台运行程序

2022/12/17 posted in  工具命令
Tags:  #Linux

三种 shell 脚本调用方法(fork, exec, source)

fork (/path/to/script.sh)

fork 是最普通的,就是直接在脚本里面用 /directory/script.sh 来调用 script.sh 这个脚本。

运行的时候开一个 sub-shell 执行调用的脚本,sub-shell 执行的时候,parent-shell 还在但会阻塞。sub-shell 执行完毕后返回 parent-shell。

sub-shell 从 parent-shell 继承环境变量,但是 sub-shell 中的环境变量不会带回 parent-shell。

exec (exec /path/to/script.sh)

exec 与 fork 不同,不需要新开一个 sub-shell 来执行被调用的脚本。被调用的脚本与父脚本在同一个 shell 内执行。但是使用 exec 调用一个新脚本以后, 父脚本中 exec 行之后的内容就不会再执行了。这是 exec 和 source 的区别。

source (source /directory/script.sh)

与 fork 的区别是不新开一个 sub-shell 来执行被调用的脚本,而是在同一个 shell 中执行。所以被调用的脚本中声明的变量和环境变量。都可以在主脚本中得到和使用。
因此我们可以通过 source 运行一个脚本,通过该脚本来设置环境变量。

在 bash 中如何让程序后台运行

非后台运行

我们在 bash 中直接运行程序时,如

$ sleep 5

就是先 fork 出一个 sub-shell,在 sub-shell 中用 exec 调用目标程序,因此目标程序执行完后,sub-shell 也会结束退出,再返回到 parent-shell 中。目标程序执行过程中 parent-shell 是阻塞的。

后台运行

如何在 bash 中让程序在后台运行而不阻塞当前 shell 呢,只需要在命令后加上&即可,如

$ sleep 5 &

对于这样的命令,系统会创建一个 sub-shell 来运行。同时,在 parent-shell 中会立刻返回 0 并且继续下面的命令执行。除此之外,在执行这个命令后,terminal 上会输出创建的 sub-shell 的进程 ID(PID)。

$ sleep 5 &
[1] 618970

注意:按照这种方法分支出去的 sub-shell 的 stdout 会仍然关联到其 parent-shell,也就是说你在当前的 terminal 中仍然可以看到这个后台进程的 stdout 输出。下面会介绍重定向输出的方法。

如果需要在 sub-shell 中执行多条命令,可以使用()包裹这些命令,如

(./myscript1.py
./myscript2.py
./myscript3.py) &

查看后台进程

通过&分支出去的 sub-shell 的 PID 被存储在一个特殊的变量$!

$ echo $!
618970

同时,你也可以通过jobs命令来检查 sub-shell 的信息

$ jobs
[1]  + running    sleep 5

对于 sub-shell,你可以通过fg命令将其拉回当前的 terminal。

进程输出重定向

有时候在 shell 命令中可能看到这样的写法,将程序输出(包括标准输出和错误输出)重定向到 /dev/null,也就是省略输出

some_command > /dev/null 2>&1

1 是系统默认代表 stdout 的值,2 代表 stderr

前面的> /dev/null好理解,> 是 1> 的简写,代表将 stdout 导向到 /dev/null
而后面的2>&1代表将 stderr 重定向到 stdout。由于 stdout 已经被重定向到 /dev/null,那么这意味着 stderr 也被重定向到了这个位置。