)
Linux命令-source在当前 Shell 环境中执行文件 简介 语法⚙️ 选项 实战示例示例 1重新加载 .bashrc最经典用法示例 2source 与 bash 执行的根本差异示例 3source 引入库函数项目级复用示例 4source 传位置参数示例 5source 用于环境切换虚拟环境示例 6source 在系统脚本中的应用示例 7source vs ./script.sh 的 shell 变量作用域示例 8source 的安全考量⚠️ 注意事项 总结 相关命令快速参考source或别名.点号是 Bash 内建命令用于在当前 Shell 进程中读取并执行指定文件中的命令。与bash script.sh的核心区别source不会启动子 Shell因此文件中的变量赋值、函数定义、cd等会持续影响当前 Shell 环境。这使得source成为加载配置文件.bashrc、.profile、引用库函数lib.sh的常用手段。关键判断修改了.bashrc→ 想立刻生效执行source ~/.bashrc而不是新开终端。 简介项目说明命令全称source含源、起源含义同义命令.点号POSIX 标准命令类型Bash 内建非外部命令所属bash/dash/zsh 等所有 POSIX shell 都支持关键行为当前 shell执行不启动子进程主要用途① 重新加载配置 ② 引入库函数 ③ 局部修改环境退出码文件最后一条命令的退出码文件不存在则 1sourcevsbash执行脚本对比场景source script.sh/. script.shbash script.sh/./script.sh启动新进程❌不启动✅ 启动子 bash修改全局变量✅影响当前 shell❌ 只在子 shell 生效函数定义✅当前 shell 可用❌ 子 shell 退出后失效cd改目录✅影响当前 shell❌ 退出后回到原目录export变量✅当前 shell 继承❌ 子 shell 退出后失效set -e选项✅影响当前 shell❌ 子 shell 独立性能极快无 fork较慢forkexec适用加载配置、库函数独立任务 语法source文件名[参数...].文件名[参数...]两种写法完全等价。source更易读POSIX 之外.兼容性更好POSIX 标准。⚙️ 选项source是 Bash 内建命令没有专门的选项标志。--help等支持来自 bash 自身。项说明文件名必需要执行的脚本路径参数...可选传给脚本的位置参数$1、$2等会被覆盖source的选项实际上由被调用文件内部的set等控制与source命令本身无关。 实战示例示例 1重新加载 .bashrc最经典用法# 1. 编辑 .bashrc$vim~/.bashrc# 加入aliasllls -alFaliasgsgit statusexportPS1[\u\h \W]\$ # 2. 当前 shell 不生效新开终端才生效# 3. **重新加载**无需新开终端$source~/.bashrc# 等价$.~/.bashrc# 4. 验证$ ll total24drwx------5alice alice4096Jan1514:00.drwxr-xr-x1root root4096Jan1409:00..-rw-------1alice alice1234Jan1514:00 .bashrc... $ gs On branch main Your branch is up todatewithorigin/main.nothing to commit, working tree clean# alias 已生效生产环境修改系统级配置如/etc/profile、/etc/bashrc后对所有用户新登录才生效要立刻生效当前用户执行source /etc/profile其他用户必须重新登录。示例 2source 与 bash 执行的根本差异# 准备测试脚本$cat/tmp/test_source.sh#!/bin/bashexportMY_VARset by scriptmy_func(){echo函数被调用:$1}cd/tmpecho当前目录:$(pwd)# 方式 1bash 执行子 shell $pwd/home/alice $bash/tmp/test_source.sh 当前目录: /tmp $pwd/home/alice# ← 没变子 shell 退出后回到原目录$echo$MY_VAR# ← 空子 shell 的 export 不会影响父 shell$ my_func bash: my_func:commandnot found# ← 函数没传过来# 方式 2source 执行当前 shell $pwd/home/alice $source/tmp/test_source.sh 当前目录: /tmp $pwd/tmp# ← 真的改了$echo$MY_VARsetby script# ← 变量生效了$ my_func hello 函数被调用: hello# ← 函数可用核心结论source是当前 shell执行副作用会留下bash是子 shell执行副作用不会留下。示例 3source 引入库函数项目级复用# 1. 创建公共库文件 $cat/opt/lib/logger.sh#!/bin/sh# 公共日志函数库LOG_FILE${LOG_FILE:-/var/log/app.log}log_info(){echo[$(date%F %T)] [INFO]$*|tee-a$LOG_FILE}log_warn(){echo[$(date%F %T)] [WARN]$*|tee-a$LOG_FILE2}log_error(){echo[$(date%F %T)] [ERROR]$*|tee-a$LOG_FILE2}log_debug(){[-n${DEBUG:-}]echo[$(date%F %T)] [DEBUG]$*|tee-a$LOG_FILE}die(){log_error$*exit1}# 2. 在主脚本中引用 $cat/opt/scripts/deploy.sh#!/bin/bashSCRIPT_DIR$(cd $(dirname$0)pwd) LIB_DIR${SCRIPT_DIR}/../lib # 引入库 source ${LIB_DIR}/logger.sh # 等价 . ${LIB_DIR}/logger.sh # 使用库函数 log_info 开始部署... log_debug DEBUG 模式开启 if ! command -v docker /dev/null; then die 未安装docker fi log_info 部署完成exit0# 3. 运行 $sudo/opt/scripts/deploy.sh[2024-01-1514:30:00][INFO]开始部署...[2024-01-1514:30:05][INFO]部署完成 $cat/var/log/app.log[2024-01-1514:30:00][INFO]开始部署...[2024-01-1514:30:05][INFO]部署完成示例 4source 传位置参数$cat/tmp/show_args.sh#!/bin/bashecho第 1 个参数:$1echo第 2 个参数:$2echo第 3 个参数:$3echo总参数数:$#echo所有参数:$# 调用$source/tmp/show_args.sh apple banana cherry 第1个参数: apple 第2个参数: banana 第3个参数: cherry 总参数数:3所有参数: apple banana cherry# 注意source 后的参数**替换**当前 shell 的 $1/$2/...# 用 set -- 后 source 可恢复$set-- alpha beta gamma $echo原参数:$原参数: alpha beta gamma $source/tmp/show_args.sh x y 第1个参数: x 第2个参数: y 第3个参数: 总参数数:2$echo当前参数:$当前参数: x y# ← 原参数 alpha/beta/gamma 被覆盖了# 这是 source 的副作用小心使用示例 5source 用于环境切换虚拟环境# 1. Python 虚拟环境激活 $whichpython3 /usr/bin/python3 $sourcevenv/bin/activate(venv)$whichpython3 /home/alice/project/venv/bin/python3# ← 切到虚拟环境$sourcevenv/bin/deactivate# 退出$whichpython3 /usr/bin/python3# venv 的 activate 本质上是$catvenv/bin/activate...VIRTUAL_ENV/home/alice/project/venvexportVIRTUAL_ENVPATH$VIRTUAL_ENV/bin:$PATHexportPATH# 修改 PATH 后python3 命令优先找 venv/bin# 2. 自定义环境切换 $cat~/env/dev.shexportNODE_ENVdevelopmentexportAPI_URLhttp://localhost:8080exportDEBUG*exportPATH$HOME/.local/bin:$PATHaliasllls -alF$cat~/env/prod.shexportNODE_ENVproductionexportAPI_URLhttps://api.example.comunsetDEBUGunaliasll2/dev/null# 切换$source~/env/dev.sh $echo$NODE_ENVdevelopment $echo$API_URLhttp://localhost:8080 $source~/env/prod.sh $echo$NODE_ENVproduction $echo$API_URLhttps://api.example.com# 快速切换环境示例 6source 在系统脚本中的应用# 1. /etc/profile 加载链 $cat/etc/profile# 读所有子配置foriin/etc/profile.d/*.sh;doif[-r$i];then.$i# source 加载fidone# 修改 /etc/profile.d/myapp.sh 后# 当前用户重新登录才生效# 立即生效$source/etc/profile# 2. .bashrc 加载链bash 启动 $cat~/.bashrc# 通常会先 source 全局配置if[-f/etc/bashrc];then./etc/bashrcfi# 然后加载用户配置if[-f~/.bash_aliases];then.~/.bash_aliasesfi# 3. Makefile 加载环境变量 $catMakefile include .env# .env 文件中 export 变量# 但 Makefile 不直接 source .env会展开变量# 改用 shell source$catMakefile include .env all:bash-csource .env ./build.sh# 或source.env./build.sh# 4. Docker entrypoint 用 source $catentrypoint.sh#!/bin/sh# 等待数据库就绪./wait-for-db.sh# 加载应用配置source/app/config/env.shexec$示例 7source vs ./script.sh 的 shell 变量作用域# 详细测试 # 准备脚本$cat/tmp/test_var.sh#!/bin/bash# 测试变量在父子 shell 的传递exportEXPORTED_VARexported_valueNORMAL_VARnormal_value# 不 exportGLOBAL_VARglobal_value# 不 export 也不带 localecho在脚本中echo EXPORTED_VAR$EXPORTED_VARecho NORMAL_VAR$NORMAL_VARecho GLOBAL_VAR$GLOBAL_VAR# 测试 1bash 子 shell 执行$echo--- bash 子 shell ---$EXPORTED_VARparent$NORMAL_VARparent$GLOBAL_VARparent$bash/tmp/test_var.sh 在脚本中EXPORTED_VARexported_value# ← 看到的是脚本自己的NORMAL_VARnormal_valueGLOBAL_VARglobal_value $echo回到父 shell$echo EXPORTED_VAR$EXPORTED_VAR# parent父 shell 的原值$echo NORMAL_VAR$NORMAL_VAR# parent$echo GLOBAL_VAR$GLOBAL_VAR# parent# 全部是父 shell 的原值**子 shell 没影响父**# 测试 2source 当前 shell 执行$echo--- source 当前 shell ---$EXPORTED_VARparent$NORMAL_VARparent$GLOBAL_VARparent$source/tmp/test_var.sh 在脚本中EXPORTED_VARexported_valueNORMAL_VARnormal_valueGLOBAL_VARglobal_value $echo回到父 shell$echo EXPORTED_VAR$EXPORTED_VAR# exported_value ← 改了$echo NORMAL_VAR$NORMAL_VAR# normal_value ← 改了$echo GLOBAL_VAR$GLOBAL_VAR# global_value ← 改了# 全部被脚本内的赋值**覆盖**示例 8source 的安全考量# 1. 加载未知脚本的风险 # source 执行**全部命令**包括 rm、curl 等危险操作$source/tmp/unknown.sh# 等价于把这些命令**粘贴到当前 shell** 执行# ⚠️ 不要 source 不可信来源的脚本# 2. 隔离测试 # 安全做法先看内容再 source$cat/tmp/unknown.sh $source/tmp/unknown.sh# 确认无恶意再执行# 或用 subshell 隔离$bash/tmp/unknown.sh# 副作用不影响当前 shell# 3. shellcheck 静态分析 $shellcheck/tmp/unknown.sh# 显示潜在问题# 4. 防止 source 破坏 $ $cat/tmp/preserve_args.sh#!/bin/bash# 保留原始位置参数ORIG_ARGS($)# 临时清空位置参数set--# 执行 source 的目标脚本source/tmp/target.sh# 恢复set--${ORIG_ARGS[]}# 5. 命名空间隔离 # source 时函数和变量**会污染**当前 shell# 解决用 (subshell) 隔离$(source /tmp/script.sh)# 在 subshell 中 source# 副作用**不会影响**当前 shell# 6. 避免循环 source # ~/.bashrc 中常见错误$cat~/.bashrcsource/etc/profile# ← 如果 /etc/profile 也 source .bashrc 会**死循环**# 解决只 source 必要的文件避免双向引用⚠️ 注意事项1. 副作用会留下source修改的变量、函数、cd、ulimit、umask等全部持续到当前 shell 结束。调试可用(source script.sh)在 subshell 中执行副作用自动丢弃。2. set -e 的传播source进来的脚本中set -e/set -u会影响当前 shell。解决在被 source 的脚本首尾用(set e u; source lib.sh; set -e -u)隔离。3.set --在 source 中覆盖位置参数如示例 4 所示source 后的$1/$2/.../$会被传进来的参数覆盖。加载库函数时避免传位置参数给库。4. 信号处理trapsource 进来的 trap会影响当前 shell。cat/tmp/lib.shtrapecho trappedINTsource/tmp/lib.sh# CtrlC 现在会触发 trapped且**当前 shell 也被影响**5.set -e在 source 函数中的边界set -e对函数内的失败会终止函数不退出 shell但对函数外的命令失败会退出。source 一个含set -e的脚本会修改整个 shell的 set 状态。6. export 与 source 顺序export只在赋值时标记为传子进程。当前 shell 的变量可见性不依赖 export。VARx# 当前 shell 可见exportVAR# 标记为传子进程echo$VAR# xsource/tmp/foo# foo 中也能看到 VAR无需 export7. 错误处理 -e 失效set -e对 source 中循环内的失败不生效set-esource/tmp/script.sh# script.sh 内的 for 循环中失败不会让当前 shell 退出8. 别名作用域alias仅在交互式shell 中展开。source进来的 alias 在非交互式调用中不展开。cat/tmp/aliases.shaliasllls -labash-csource /tmp/aliases.sh; ll# ll 不展开alias 失效9. PATH 不会自动 sourcesource不会自动把当前目录加入 PATH。./script.sh与source ./script.sh都不需要 PATH 修改。10. POSIX 标准POSIX 严格只支持. filenamesource是Bash 扩展。可移植脚本用.source .bashrc在 dash 中不存在。 总结source.是当前 shell 加载并执行的标准操作与子 shell 执行形成对照。本节要点核心场景① 重新加载配置source ~/.bashrc② 引入库函数source lib.sh③ 切换环境Python venv与 bash 的区别source不启动子 shell副作用留下使用技巧source ~/.bashrc修改后立即生效source env/dev.sh切换环境source lib.sh复用函数(source script.sh)隔离副作用风险source不可信脚本等于直接执行会污染 $、set、trap最终建议加载配置必须用source运行独立任务用bash或./script.sh复用库用source lib 目录结构隔离测试用(source script.sh)。 相关命令命令用途.(点号)POSIX 等价sourcebash script.sh子 shell 执行./script.sh子 shell 执行需执行权限exec command替换当前 shell 进程不返回eval拼接并执行字符串set设置 shell 选项unset取消变量/函数export标记变量传子进程declare/typeset声明变量属性command -v CMD检查命令是否存在shellcheck静态分析shoptbash 选项仅 bash