Shell—关于source,Bash如何执行

  通过对一个脚本问题的分析,发现了自己的一个知识误区,我想,有必要写篇博客总结一下。

关于source

  source test.sh. test.sh 二者用法相同。是读取脚本test.sh中的内容,依次在当前脚本中执行,且不会建立新的子shell去执行。被引用脚本 test.sh中的所有新建、改变变量的语句都会保存在当前shell里面,并被执行。
   一般,在被引用脚本 test.sh中会封装一个公用的代码或是校验类的接口函数,供其他脚本调用。
  尤其需要理解区分的是,source不同于 “./ test.sh” 和 “/bin/bash test.sh”,此二者有本质的区别,后者是在当前脚本中执行子shell,会产生新的进程来执行,而且在父shell中不能调用子shell中包含的函数接口。而source之后的文件内容已被加载到当前脚本中,就可以调用其内部定义的函数。

本文测试的 test.sh 脚本如下,作为被引用的脚本文件

#!/bin/bash
echo "Enter test.sh"
function func1()
{
    echo "enter function 1"
}
function func2()
{
    echo " $1: source $2 "
    echo "Exit test.sh"
    exit 0
}
echo "Exit test.sh ~~~"

当执行exec.sh脚本时,exec.sh 中执行 ./test.sh,结果如下
@xiaoma
验证:在父shell中不能调用子shell中包含的函数接口

bash如何执行

  通过分析源码,bash是把执行的shell中的内容存储到hash表。source作为内置命令,其实现也在bash源码中(builtins/source.def 内置方法的文件都在builtins目录),当bash执行到source命令时,会将引用的脚本文件内容读入一个缓冲区,保存于一段临时开辟的hash表中,然后通过调用函数push_scope(VC_BLTNENV, tempporary_env)push到当前脚本的上下文中,在哪里引用,就在哪加入当前脚本的上下文。最后,bash依次往下执行当前脚本。
本文中测试的当前脚本 source.sh 如下:

#!/bin/bash

if [ $# -ne 1 ]
then
	echo "Usage: $0 source_file"
fi
source_file=$1
echo "First source $source_file"
source $source_file
echo "Exec func1 function"
func1
echo "Second source $source_file"
. $source_file
echo "Exec func2 function"
func2 "$0 $source_file"
echo "Exit source.sh"  # func2 中存在 exit 0, bash执行不到这里,因此不会打印

在命令行执行 ./source.sh test.sh 打印如下:
@xiaoma
Bash执行过程如下:
@xiaoma
从上图看得出来,每一次source,当前执行脚本中就会重新读取被引用脚本 test.sh的内容并执行,因此在实际写shell时,要避免多次source一个文件,此处是为了示例source执行的过程。

  对于简单的命令,要更加理解到位,不然还是会犯一些低级的小错误。

发布了52 篇原创文章 · 获赞 81 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/xiaoma_2018/article/details/95241905
今日推荐