在 Bash 中,执行脚本可以通过多种方式,其中最常见的两种是使用 bash
直接运行脚本和使用 source
命令(或 .
,即点命令)来执行。这两种方式有着根本的区别,它们对脚本的影响和脚本对环境的影响也不同。
使用 bash
执行脚本
当你使用 bash script.sh
或者通过使脚本可执行后直接运行脚本(例如,通过 chmod +x script.sh
然后执行 ./script.sh
)时,发生以下事情:
- 子进程创建:Bash 会创建一个新的子进程来执行脚本。这个子进程是当前 shell 的副本。
- 环境隔离:在子进程中进行的所有变更(例如,变量设置、导出的环境变量、目录更改等)只在该子进程中有效,并且在脚本执行完成后随进程终止而消失。
- 返回状态 :可以通过
$?
捕获脚本执行后的退出状态码,这对于检查脚本是否成功执行非常有用。
使用 source
执行脚本
当你使用 source script.sh
或 . script.sh
执行脚本时,会发生不同的行为:
- 当前进程执行:脚本在当前 shell 进程中执行,而不是创建新的子进程。
- 环境持久化:所有在脚本中进行的变更,如设置或修改变量,都会直接影响当前的 shell 环境。这意味着任何新的环境变量或更改都将在脚本完成后保留下来。
- 无返回状态 :由于脚本是在当前 shell 中执行的,所以不能捕获退出状态(没有子进程的退出状态),但你可以在脚本中使用
return
语句来提供类似的功能。
实际应用中的选择
- 初始化环境 :如果你需要执行一些设置环境变量的操作或定义函数,这些需要在当前会话中持续存在,那么应该使用
source
。这常见于配置文件,如.bashrc
或.profile
。 - 独立的脚本执行:如果你想运行一个脚本,该脚本完成一些操作并且不希望其更改影响当前环境,如安装脚本、数据处理脚本等,则应直接执行脚本。
示例说明
假设有一个脚本 setenv.sh
,内容如下:
bash
#!/bin/bash
export PATH="/new/path:$PATH"
alias ll='ls -l'
- 使用
bash setenv.sh
执行时,设置的环境变量和别名仅在脚本运行期间有效,脚本执行结束后这些设置会消失。 - 使用
source setenv.sh
或. setenv.sh
执行时,PATH
环境变量和ll
别名的更改将影响当前 shell 的会话,即使脚本执行结束后这些更改仍然有效。
这些差异使得 source
命令特别适用于那些需要修改或扩展用户环境的脚本,而直接执行则更适用于那些需要保持环境干净、操作独立的场合。
在 Bash 脚本中,$0
和 ${BASH_SOURCE[0]}
是两个用来标识当前执行脚本的路径和名称的变量,但它们在某些情况下的表现有所不同。理解这些差异对于编写能正确理解其执行环境的脚本是非常重要的。
$0
变量
- 定义 :
$0
是当前正在执行的 shell 或脚本的名称。它通常用于在脚本中获取当前执行文件的名称。 - 行为 :
- 在直接执行脚本时(如
./script.sh
或bash script.sh
),$0
通常会显示脚本的路径。 - 在通过
source
或点命令(.
)执行脚本时,$0
不会变为脚本名称,而是保持为调用它的 shell 的名称(例如bash
、sh
等)。
- 在直接执行脚本时(如
${BASH_SOURCE[0]}
变量
- 定义 :
${BASH_SOURCE[0]}
是一个 Bash 特有的数组变量,它在任何时候都包含一个脚本的源文件名。即使在函数内部,它也能准确反映出函数所在的脚本文件。 - 行为 :
- 无论脚本是被执行还是被
source
,${BASH_SOURCE[0]}
总是指向脚本本身的路径。这使得它在需要精确知道脚本位置的情况下非常有用,尤其是在脚本被source
或从另一个脚本调用时。
- 无论脚本是被执行还是被
使用场景比较
获取脚本路径的正确方法
如果你需要在脚本中获取其自身的路径,特别是在不确定脚本将如何被调用(直接执行或被 source
)的情况下,最好使用 ${BASH_SOURCE[0]}
。这样可以保证无论脚本是如何被调用的,都能正确获得其路径。
示例
下面的 Bash 脚本示例演示了 $0
和 ${BASH_SOURCE[0]}
在不同情况下的行为:
bash
#!/bin/bash
echo "Using \$0: $0"
echo "Using BASH_SOURCE: ${BASH_SOURCE[0]}"
- 当你直接执行这个脚本(比如
./test.sh
)时,两者都会显示脚本路径。 - 当你使用
source test.sh
执行这个脚本时,$0
会显示为bash
,而${BASH_SOURCE[0]}
依然显示脚本的路径。
结论
对于大多数编写 Bash 脚本的场景,特别是需要准确获得脚本文件路径的情况,建议使用 ${BASH_SOURCE[0]}
,因为它在各种情况下都能提供一致和准确的结果。而 $0
可用于获取正在执行的 shell 的名称或在直接执行脚本时获取脚本名称,但其在被 source
时的行为可能会导致混淆。