Skip to content

LV100-子shell

一、子 shell?

上边的文件包含会把另一个脚本的内容复制到此脚本中执行,就很类似于 C 语言中的 include,还有其他方法可以执行其他脚本吗?还有以下两种方式:

  • fork: 如果脚本有执行权限的话,path/to/foo.sh 。如果没有的话就这样:sh path/to/foo.sh。
  • exec: exec path/to/foo.sh

这两种有什么特点?与上边的 source 有什么不同?我们来看一看吧

1. fork

1.1 使用格式

shell
path/to/foo.sh     # 有执行权限
sh path/to/foo.sh  # 无执行权限

执行方式:在主脚本中写所要调用脚本的路径,比如 /home/hk/1sharedfiles/6temp/file1.sh

特点:

(1)运行主脚本运行的的终端会新开一个子 shell 来执行脚本 first.sh;

(2)子 shell 执行的时候,父 shell 还在;

(3)子 shell 执行完毕后返回父 shell,子 shell 会继承父 shell 的环境变量,但是子 shell 中的环境变量不会带回父 shell

1.2 使用实例

  • 主调 shell 脚本:file1.sh
shell
#!/bin/bash
# filename: file1.sh

A=999
echo "before fork: PID for file1.sh = $$"
export A
echo "In file1.sh: variable file1_variable=$A"

echo -e "==>>> using fork start\n"
/home/hk/1sharedfiles/6temp/file2.sh

echo "after exec/source/fork: PID for file1.sh = $$"
echo -e "In file1.sh: variable file1_variable=$A\n"
  • 被调 shell 脚本:file2.sh
shell
#!/bin/bash
# filename: file2.sh

echo "PID for file2.sh = $$"
echo "In for file2.sh get variable file1_variable=$A from file1.sh"
A=111
export A
echo -e "In for file2_variable.sh: variable for file2_variable=$A\n"
  • 执行结果如下
shell
hk@ubuntu-22-04:~/1sharedfiles/6temp$ ./file1.sh 
before fork: PID for file1.sh = 6773
In file1.sh: variable file1_variable=999
==>>> using fork start

PID for file2.sh = 6774
In for file2.sh get variable file1_variable=999 from file1.sh
In for file2_variable.sh: variable for file2_variable=111

after exec/source/fork: PID for file1.sh = 6773
In file1.sh: variable file1_variable=999

2. exec

2.1 使用格式

shell
exec script_path

执行方式:exec + 脚本路径

特点:

(1)运行主脚本时不会新开一个子 shell 来执行被调用脚本 first.sh,被调用的脚本与主脚本在同一个 Shell 内执行,所以被调用的脚本中声明的变量和环境变量, 都可以在主脚本中进行获取和使用。

(2)使用 exec 调用一个新脚本以后, 父脚本中 exec 行之后的内容就不会再执行。

2.2 使用实例

  • 主调 shell 脚本:file1.sh
shell
#!/bin/bash
# filename: file1.sh

A=999
echo "before fork: PID for file1.sh = $$"
export A
echo "In file1.sh: variable file1_variable=$A"

echo -e "==>>> using fork start\n"
exec /home/hk/1sharedfiles/6temp/file2.sh

echo "after exec/source/fork: PID for file1.sh = $$"
echo -e "In file1.sh: variable file1_variable=$A\n"
  • 被调 shell 脚本:file2.sh
shell
#!/bin/bash
# filename: file2.sh

echo "PID for file2.sh = $$"
echo "In for file2.sh get variable file1_variable=$A from file1.sh"
A=111
export A
echo -e "In for file2_variable.sh: variable for file2_variable=$A\n"
  • 执行结果如下
shell
hk@ubuntu-22-04:~/1sharedfiles/6temp$ ./file1.sh 
before fork: PID for file1.sh = 6808
In file1.sh: variable file1_variable=999
==>>> using fork start

PID for file2.sh = 6808
In for file2.sh get variable file1_variable=999 from file1.sh
In for file2_variable.sh: variable for file2_variable=111

3. source

fork 的区别是不新开一个子 Shell 来执行被调用的脚本,而是在同一个 Shell 中执行. 所以被调用的脚本中声明的变量和环境变量, 都可以在主脚本中进行获取和使用。

其实从命名上可以感知到其中的细微区别,下面通过两个脚本来体会三种调用方式的不同:

3.1 使用格式

shell
source script_path
. script_path

执行方式:source(或者 . ) + 脚本路径

特点:

(1)同 exec 的特点(1)即运行主脚本时不会新开一个子 shell 来执行被调用脚本 file2.sh,被调用的脚本与主脚本在同一个 shell 内执行。

(2)使用 source 调用一个新脚本以后, 主脚本中 exec 行之后的内容还会执行。

(3)被调用的脚本中声明的变量和环境变量, 都可以在主脚本中进行获取和使用。

3.2 使用实例

  • 主调 shell 脚本:file1.sh
shell
#!/bin/bash
# filename: file1.sh

A=999
echo "before fork: PID for file1.sh = $$"
export A
echo "In file1.sh: variable file1_variable=$A"

echo -e "==>>> using fork start\n"
. /home/hk/1sharedfiles/6temp/file2.sh

echo "after exec/source/fork: PID for file1.sh = $$"
echo -e "In file1.sh: variable file1_variable=$A\n"
  • 被调 shell 脚本:file2.sh
shell
#!/bin/bash
# filename: file2.sh

echo "PID for file2.sh = $$"
echo "In for file2.sh get variable file1_variable=$A from file1.sh"
A=111
export A
echo -e "In for file2_variable.sh: variable for file2_variable=$A\n"
  • 执行结果如下
shell
hk@ubuntu-22-04:~/1sharedfiles/6temp$ ./file1.sh 
before fork: PID for file1.sh = 6840
In file1.sh: variable file1_variable=999
==>>> using fork start

PID for file2.sh = 6840
In for file2.sh get variable file1_variable=999 from file1.sh
In for file2_variable.sh: variable for file2_variable=111

after exec/source/fork: PID for file1.sh = 6840
In file1.sh: variable file1_variable=111

4. ()括号

() 可以用来创建子shell,这样在子 shell中执行命令,不会影响当前 shell 的环境(目录、环境变量等)。常用于临时改变环境而不影响当前 shell。

shell
# 圆括号会创建一个子 shell 来执行其中的命令
(    
    cd /tmp
    echo "当前目录: $(pwd)"
    var="子 shell 中的变量"
)

# 父 shell 的环境不受影响
echo "回到原目录: $(pwd)"   # 仍在原目录
echo "var = $var"           # 空,因为 var 在子 shell 中定义