Bash脚本跨目录source异常:为何需先source同目录脚本?
让我们拆解一下你遇到的问题:错误提示./utils/jwt/../id/create_new_user.sh: line 9: ./utils/jwt/create_new_user.sh: No such file or directory说明,你的create_new_user.sh脚本第9行尝试访问一个不存在的路径,而source rand.sh后这个路径突然变得有效——核心原因是**create_new_user.sh依赖了rand.sh带来的环境变更或变量定义**,具体分两种常见情况:
情况1:rand.sh修改了当前工作目录
如果rand.sh里有类似这样的代码:
# rand.sh 中的内容 cd "$(dirname "$BASH_SOURCE")"
source它之后,你的当前工作目录会从项目根目录(/Users/dank/code/<PROJECT>)切换到utils/jwt/目录。此时再source ../id/create_new_user.sh,create_new_user.sh里的相对路径会基于utils/jwt/解析。如果create_new_user.sh第9行的路径是写错的(比如本该用../jwt/xxx.sh却写成了./utils/jwt/xxx.sh),切换工作目录后反而“歪打正着”让错误路径指向了正确的文件。
情况2:create_new_user.sh依赖rand.sh定义的路径变量
如果rand.sh中定义了路径相关的变量(比如项目根目录、工具目录),例如:
# rand.sh 中的内容 JWT_DIR=$(dirname "$BASH_SOURCE") PROJECT_ROOT="$JWT_DIR/../.."
而create_new_user.sh第9行直接使用了这个未在自身脚本中定义的变量,比如:
# create_new_user.sh 第9行(错误写法) source "$PROJECT_ROOT/utils/jwt/create_new_user.sh"
当不source rand.sh时,PROJECT_ROOT变量未定义,Bash会将其视为空字符串,导致路径被解析成./utils/jwt/create_new_user.sh——这个文件显然不存在,所以报错。
正确的解决方案:让脚本独立解析自身路径
解决这个问题的核心是让每个脚本都能独立获取自己的绝对路径,不依赖其他脚本的环境变更或变量:
- 在
create_new_user.sh的开头添加路径解析代码:
# create_new_user.sh 开头 # 获取当前脚本的绝对目录路径 CREATE_USER_DIR=$(dirname "$BASH_SOURCE") CREATE_USER_DIR=$(cd "$CREATE_USER_DIR" && pwd) # 如果需要引用rand.sh,用绝对路径构建 source "$CREATE_USER_DIR/../jwt/rand.sh"
- 在
get_jwt.sh中直接正确sourcecreate_new_user.sh,无需先sourcerand.sh:
# get_jwt.sh 中的正确写法 JWT_DIR=$(dirname "$BASH_SOURCE") JWT_DIR=$(cd "$JWT_DIR" && pwd) source "$JWT_DIR/../id/create_new_user.sh"
这样每个脚本都能独立解析自己的路径,不会依赖其他脚本的环境修改,也就不需要先source rand.sh了。
内容的提问来源于stack exchange,提问作者danksim

