在同一个目录下有两个脚本,a.sh和b.sh,脚本内容如下:
a.sh:

echo "test for a"
source b.sh

b.sh:

echo "test for b"

使用bash a.sh 返回正确结果。
而使用sh a.sh返回结果如下:
test for a
a.sh: line 2: source: b.sh: file not found
明显脚本运行过程中,没有找到文件b.sh,将a.sh脚本内容修改为如下:

echo "test for a"
source ./b.sh

再次使用sh a.sh 又可以正常执行了,这是为什么呢?

问题就出在sh与bash执行脚本的区别。
  首先要明确重要的一点:/bin/sh 虽然是/bin/bash的软连接,但这个软连接很特殊,它并不仅仅只是一个链接,sh不等于bash。如果你在CentOS下使用man sh可以找到这句话:
Bash can be configured to be POSIX-conformant by default.
这说明sh 等于 bash -posix 也就是说使用sh来执行一个脚本,所以使用sh a.sh的效果等同于bash -posix a.sh,虽然大部分情况下等于使用bash来执行脚本,但启用了bash的posix模式,也可以理解为posix标准。那么就要遵循这个标准下的要求。
现在来man bash在关于source命令的文档中找到这么一句话:
When bash is not in posix mode, the current directory is searched if no file is found in PATH.
如果bash不是运行在posix模式下,当文件名最为source的参数系统如果在PATH中,也就是系统变量中找不到这个文件时会在当前目录下查找这个文件。
所以在不使用posix模式的情况下 a.sh脚本中的source b.sh不会出错,因为即使在PATH中找不到,也会在当前目录中进行查找。但如果使用了posix模式,可以在google中找到关于bash posix mode的内容,其中有一条:
The . and source builtins do not search the current directory for the filename argument if it is not found by searching PATH.
.也就是source这种内建命令在使用文件名作为参数时,如果在PATH中无法找到,将不会在当前目录自动进行查找。
这就是问题的关键,使用了sh 执行a.sh,脚本中source b.sh中的b.sh既不会在PATH中被找到也不会在当前目录下被找到,那么bash只会返回
b.sh: file not found
但如果a.sh写成这样 source ./b.sh
这就不一样了,这等于给source提供了一个该文件的路径,虽然是相对路径,但bash是可以根据脚本本身执行的位置来找到b.sh的,所以就不会出错了。

总结:所以一般情况下,在Linux中执行一个bash的脚本,我们都会使用bash去执行,就是为了避免这种奇怪问题的产生。

关于bash posix mode的相关信息你可以在这里找到