linux BASH_SOURCE[0]

本文介绍了一种在Shell脚本中获取当前执行文件所在路径的方法。通过使用BASH_SOURCE数组结合dirname命令和cd命令,可以方便地定位到脚本所在的目录,并输出其绝对路径。
BASH_SOURCE[0] BASH_SOURCE[0] 等价于 BASH_SOURCE, 取得当前执行的shell文件所在的路径及文件名。

在目录/home/sam/linux编程练习/Shell下新建脚本test.sh:

#!/bin/bash

DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )/../" && pwd )"
# DIR=$( cd "$( dirname ${BASH_SOURCE[0]} )/../" && pwd )
# DIR=`cd $( dirname ${BASH_SOURCE[0]} )/../ && pwd`
echo $DIR
echo "ok"

执行的时候,需要棵执行权限:chmod +x test.sh 然后执行./test.sh 而不是 sh ./test.sh

经测试以上写都正确:输出

/home/sam/linux编程练习
ok

其实就是一个:1.取得当前执行的shell文件所在的完整路径 2. 执行dirname,并进入父级目录 3. 打印当前工作目录 的过程

# echo "${BASH_SOURCE[0]}"
# echo "${BASH_SOURCE}"
# echo "$( dirname "${BASH_SOURCE[0]}" )"
# DIR="$( cd "$( dirname ${BASH_SOURCE[0]} )" && pwd )"
# echo $DIR
<think>我们正在讨论Bash脚本的执行行为,特别是当脚本被直接运行(直接执行)或被source(在当前shell环境中执行)时的差异。 用户的问题:Understanding or debugging a Bash script execution behavior 请问bash script execution behavior when sourced or run directly 我们需要解释两种执行方式的区别,并说明如何在一个脚本中检测它是被source还是被直接运行。 关键点: 1. 直接运行:创建一个新的子shell来执行脚本,脚本中定义的变量、函数等在脚本结束后不会影响当前shell环境。 2. source(或.): 在当前shell环境中执行脚本,因此脚本中定义的变量、函数等会保留在当前shell中。 另外,我们经常需要在一个脚本中判断它是被source还是被直接运行。常用的方法是比较`$0`和`$BASH_SOURCE`(或使用`[[ $0 != $BASH_SOURCE ]]`)以及检查`$_`(但`$_`在source时通常是当前shell的路径,而直接运行时是脚本路径)。更可靠的方法是使用`${BASH_SOURCE[-1]}`(对于bash)和`$0`的比较。 一个常见的模式是: if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then echo "脚本被直接执行" # 直接执行时的逻辑 else echo "脚本被source" # 被source时的逻辑 fi 注意:`${BASH_SOURCE[0]}`在直接执行时是脚本的路径,而在source时也是脚本的路径。但是`$0`在直接执行时是脚本的路径,而在source时是当前shell的名称(如bash)或者脚本路径(在某些情况下,比如在脚本中source另一个脚本,情况会复杂)。 然而,更准确的方法是:在直接执行时,`${BASH_SOURCE[0]}`和`$0`是相同的;而在source时,`${BASH_SOURCE[0]}`是脚本的路径,但`$0`是父脚本的路径(或当前shell的名称,如果是在交互式shell中source的话)。 因此,我们通常使用上述比较。 另一种方法是检查`$0`是否包含字符串`bash`(但不可靠,因为用户可能用其他shell或者脚本路径包含bash字符串)。 我们还可以使用`[[ $- == *i* ]]`来检查是否在交互式shell中,但这与source和直接运行的关系不是直接的。 因此,我们重点介绍第一种方法。 此外,我们还可以利用`${BASH_SOURCE[-1]}`(数组最后一个元素)来获取最底层的脚本路径。 但为了简单和可移植性,我们使用上述比较。 下面我们给出一个示例脚本,展示如何检测并演示两种执行方式下的行为差异。</think>### Bash脚本执行行为分析(直接执行 vs. sourced) #### 1. **核心区别** - **直接执行** (`./script.sh` 或 `bash script.sh`): - 创建新的子Shell进程执行脚本 - 脚本结束后,所有变量、函数和修改的环境变量**自动销毁** - 脚本内`exit`会终止子Shell进程 - 示例验证: ```bash # 脚本内容: test.sh #!/bin/bash var="Hello" echo "子Shell PID: $$" ``` 运行结果: ```bash $ ./test.sh # 输出子Shell PID(不同于当前终端PID) $ echo $var # 输出空值(变量已销毁) ``` - **Sourced执行** (`source script.sh` 或 `. script.sh`): - 在**当前Shell进程**中直接执行 - 脚本中的变量、函数和环境变量修改**会保留**到当前Shell - 脚本内`exit`会**关闭当前终端会话** - 示例验证: ```bash $ source test.sh # 输出当前终端PID $ echo $var # 输出 "Hello"(变量保留) ``` #### 2. **关键行为差异** | 特性 | 直接执行 | Sourced执行 | |---------------------|----------------------------|--------------------------| | Shell进程 | 新建子Shell | 当前Shell | | 变量作用域 | 脚本结束后销毁 | 保留到当前Shell | | `exit`命令 | 终止子Shell | **终止当前终端** | | `$0` 的值 | 脚本路径 (如 `./test.sh`) | 当前Shell名称 (如 `bash`)| | 修改环境变量 (`export`) | 仅影响子Shell | 影响当前Shell | #### 3. **检测执行方式的方法** 在脚本中添加以下代码可自动识别执行方式: ```bash if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then echo "▶ 正在直接执行" # 直接执行专用代码 else echo "▶ 正在被sourced" # sourced专用代码 fi ``` **原理**: - `${BASH_SOURCE[0]}` 始终表示脚本路径 - `$0` 在直接执行时为脚本路径,在sourced时为父Shell名称 #### 4. **典型应用场景** - **适合直接执行**: - 独立工具程序 - 需隔离环境的任务(如批量文件处理) - 避免污染当前Shell的场景 - **适合sourced执行**: - 环境配置脚本(如 `~/.bashrc`) - 函数库加载(定义可重用的函数) - 修改当前工作目录或环境变量(如 `cd project && source venv/bin/activate`) #### 5. **调试技巧** - **检查进程树**: ```bash # 脚本中插入: ps -f --ppid $$ # 直接执行显示子进程,sourced显示当前进程 ``` - **跟踪变量**: ```bash # 使用 declare -p 检查变量定义位置 declare -p var_name ``` - **安全防护**: ```bash # 防止sourced时意外exit if [[ "${BASH_SOURCE[0]}" != "${0}" ]]; then return # 用return替代exit fi ``` > 关键参考:Linux Bash手册中 *INVOCATION* 和 *COMMAND EXECUTION ENVIRONMENT* 章节[^1],POSIX Shell标准规范[^2]
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值