当前位置: 首页 > news >正文

./main.sh vs source main.sh 讲透

在终端里跑脚本的可能写法:

  • ./main.sh
  • source main.sh(或 . main.sh
  • bash main.sh / sh main.sh
  • 甚至 exec ./main.shnohup ./main.sh &

它们看起来都“能跑”,但性质上有差异。讲清楚避免经典踩坑。

差异的核心只有三点:

  1. 在哪个进程里执行?(当前 shell 还是子 shell)
  2. 会不会影响当前环境?(cd / export / 函数 / alias 等是否保留)
  3. 用哪个解释器?(shebang 决定还是你当前 shell 决定)

1. ./main.sh:把脚本当“程序”执行

./main.sh 会启动一个新的进程来运行脚本(可以理解为子 shell / 子进程)。

特性

  • 需要可执行权限:通常要 chmod +x main.sh
  • 解释器由 shebang 决定:脚本第一行例如:#!/usr/bin/env bash
  • 不会影响当前终端环境:脚本里 cd、变量赋值、export、函数定义……对你的当前 shell 都不会生效
  • echo $? 看到的是脚本退出码

适用场景

  • 构建/部署/批处理
  • 只想跑一次任务,不希望“污染”当前终端

2. source main.sh / . main.sh:把脚本“引入”当前 shell

source(或点号 .)不是启动新进程,而是把文件内容当作命令,在当前 shell 进程里逐行执行

特性

  • 不需要可执行权限(只要可读即可)
  • 会影响当前终端环境:脚本里做的 cd、变量、export、函数、alias、set -oulimit 等都会留下来
  • 脚本里的 exit 会直接把你的终端退出。因为脚本就是在当前 shell 里跑的,被 source 的脚本要提前结束,应该用 return(或把逻辑写到函数里)
  • 解释器不是 shebang 决定的:而是你的当前 shell(bash/zsh 等)。当然这个脚本的语法必须兼容你当前 shell

适用场景

  • 加载环境变量(如 venv/bin/activateconda
  • 设置 PATH / 代理 / 函数工具库
  • 需要让脚本的改动“留在当前终端”里

经典案例

假设脚本 main.sh 内容如下:

cd /tmp
FOO=bar
export BAR=baz

./main.sh 运行

./main.sh
pwd         # 仍然是原目录
echo "$FOO" # 空
echo "$BAR" # 空(通常)

因为这些变更发生在子进程里,脚本结束后子进程消失,环境也就消失了。

source main.sh 运行

source main.sh
pwd         # 变成 /tmp
echo "$FOO" # bar
echo "$BAR" # baz

因为变更发生在当前 shell,自然“留下来了”。

其他类似命令

3. bash main.sh:强制用 Bash 执行(子进程)

特性

  • ./main.sh类似,在子进程里跑:对当前 shell 不生效。不过不需要可执行权限
  • 强制用 bash 解析(无视 shebang)

适用场景

  • 脚本使用 bash 特性(数组、[[ ]]set -o pipefail
  • 你不想改权限或不想依赖 shebang

4. main.sh:错误写法

你可能想要./main.sh,但直接写main.sh不对,这是因为大多数系统默认 当前目录不在 PATH(安全原因)。

  • 当你在 Shell 中直接输入一个命令时,如果命令中包含斜杠,Shell 会将其视为路径,直接访问该位置的文件。

  • 无斜杠则触发 PATH 查找:如果命令是单纯的 main.sh,Shell 会将其理解为命令名,并在 PATH 环境变量所列出的目录中按顺序查找。出于安全考虑,绝大多数系统默认不将当前目录(.)加入 PATH

为什么作为参数时又不需要 ./ 了?

main.sh 不是命令行的第一个“单词”时,它的解析者不再是当前的 Shell,而是前面的命令。

  • bash main.sh:这里 bash 本身是一个命令,Shell 通过 PATH 找到了 /bin/bash 并启动它。main.sh 是作为参数传递给 bash 解释器的。bash 在处理这个参数时,会将其直接当作文件路径来寻找,而文件路径的查找默认始于当前目录source main.sh. main.sh同理

5. exec ./main.sh:用脚本替换当前 shell 进程

exec 会让脚本进程替换当前 shell 进程,而不是新开子进程。

  • 不会“回来”到原来的 shell(因为它被替换了)
  • 常用于:容器 entrypoint、进程接管、长驻前台任务

6. ( ... ):括号创建子 shell,隔离副作用

括号会创建一个子 shell,里面的 cd、变量等不会影响外部。

( source main.sh )
# main.sh 里的 cd/export 不会污染当前 shell
需求 推荐写法
只想跑脚本,不影响当前终端 ./main.shbash main.sh
脚本要修改当前终端环境(export / cd / 函数) source main.sh / . main.sh
脚本依赖 bash 特性,且不想 chmod bash main.sh
追求 POSIX 可移植 sh main.sh(确保脚本兼容)
想执行但不污染当前 shell ( ./main.sh )( source main.sh )
要用脚本接管当前进程 exec ./main.sh
要后台运行 / 断开终端仍运行 nohup ./main.sh & / setsid
http://www.jsqmd.com/news/279323/

相关文章:

  • 运维系列【仅供参考】:Ubuntu16.04升级到18.04--检查更新时出现问题--解决方法
  • 【消息队列】Kafka 核心概念深度解析
  • 强烈安利专科生必用AI论文写作软件TOP9
  • BthpanContextHandler.dll文件丢失找不到 免费下载方法分享
  • springboot174基于Java的高校学生课程预约成绩统计系统的设计与实现
  • 深入Kali Linux:高级渗透测试技术详解:无线网络高级渗透测试、破解WPAWPA2加密
  • MCP协议核心技术揭秘:打通大模型与动态数据源的最后1公里
  • Android和IOS 移动应用App图标生成与使用 Assets.car生成
  • FSMN VAD异步处理机制:高并发请求应对策略
  • 麦橘超然服务无法启动?Python依赖冲突解决步骤详解
  • springboot175基于springboot商场停车场预约服务管理信息系统
  • 开发者必看:Qwen3-1.7B镜像开箱即用部署实战推荐
  • Z-Image-Turbo高性能部署:DiT架构下1024分辨率生成实测
  • bthserv.dll文件丢失找不到 免费下载方法分享
  • Z-Image-Turbo值得入手吗?消费级显卡实测性能完整报告
  • springboot176基于JSP的教师科研项目报名系统
  • 渗透测试常用反弹shell方法(如何渗透测试反弹shell)—Windows篇渗透测试!
  • CosyVoice2-0.5B免费部署方案:无需高端GPU也能运行
  • 输电线路巡检缺陷数据集是支撑巡检AI算法(如缺陷检测、分类、定位)研发与验证的核心基础
  • 【RCE剖析】从0到1讲解RCE漏洞绕过,Windows与Linux的RCE漏洞绕过方式总结
  • cabview.dll文件丢失找不到问题 免费下载方法分享
  • Claude Desktop自定义MCP Server路径不生效?(深度排查指南)
  • IT内卷时代,普通Java程序员面试前如何查漏补缺?
  • 【专家亲授】:dify集成企业微信群聊机器人的最佳实践(附完整代码示例)
  • 渗透测试怎么做?看完这个我也学会了!一文带你零基础黑客渗透入门到精通!
  • CallButtons.dll文件丢失找不到问题 免费下载方法分享
  • Paraformer-large能否替代商业ASR?成本效益全面对比
  • Java程序员如何深入学习JVM底层原理?
  • cv_unet_image-matting实战案例:电商平台商品图自动化流程
  • 【MCP服务器资源管理终极指南】:动态定义resources的5大核心技巧揭秘