当前位置:首页 > 技术 > 正文内容

Linux Shell 脚本执行方式详解:source、sh、bash 与 ./ 的核心差异

访客 技术 2026年7月7日 1

在 Linux 系统中,执行 Shell 脚本有多种常见方式,包括 sourceshbash 以及 ./。尽管它们都能让脚本运行起来,但其背后的进程模型、环境变量作用域以及对文件权限的要求却大相径庭。理解这些差异对于编写健壮的自动化脚本和进行系统管理至关重要。

1. source 命令与点号 (.) 简写

使用 source 命令或其简写形式 . 执行脚本时,系统会在当前 Shell 进程中读取并执行脚本内容。这种方式不会创建新的子进程。

source script.sh
# 或者使用简写(注意点后必须有一个空格)
. script.sh

核心特性:

  • 环境共享:脚本中对环境变量的修改、函数的定义以及目录的切换,都会直接影响当前 Shell 环境。
  • 权限要求:由于只是在当前 Shell 中读取文件内容并解释执行,因此脚本文件不需要具备可执行权限(x 权限),只需有读权限(r 权限)即可。

2. sh 与 bash 命令

通过显式调用 shbash 解释器来运行脚本,系统会启动一个新的子 Shell(Subshell) 作为子进程来执行该脚本。

sh script.sh
bash script.sh

核心特性:

  • 环境隔离:子 Shell 会继承父 Shell 的环境变量(仅限已 export 的变量),但在子 Shell 内部对变量所做的任何修改、新增的变量或函数,在脚本执行完毕、子进程退出后,都不会影响父 Shell 的环境。
  • 权限要求:source 类似,解释器直接读取文件内容,因此脚本文件不需要可执行权限。
  • 解释器差异:sh 通常指向系统默认的 POSIX 兼容 Shell(如 dash),而 bash 则明确使用 Bash 解释器,支持更多扩展特性。

3. 直接执行 (./)

使用 ./ 或绝对/相对路径直接运行脚本,同样会派生一个子 Shell 进程来执行。

./script.sh

核心特性:

  • 环境隔离:sh/bash 方式相同,子进程的环境变化不会反映到父进程中。
  • 权限要求:操作系统在直接执行文件时,会检查文件的权限位。因此,脚本文件必须具有可执行权限。若权限不足,需使用 chmod +x script.sh 进行授权。
  • 别名(Alias)扩展限制:在非交互式 Shell(即通过 ./ 运行的脚本)中,默认不会展开 alias。如果脚本中依赖 alias,必须显式开启别名扩展功能:
shopt -s expand_aliases

4. 深入底层:Fork、Source 与 Exec 机制

为了更透彻地理解上述命令的本质,我们可以从操作系统进程管理的角度,将脚本执行方式归纳为三种底层机制:

  • Fork(默认派生):父进程(Parent Process)通过 fork() 系统调用创建一个子进程(Child Process)来执行脚本。子进程拥有独立的内存空间和环境副本。子进程执行完毕后控制权交还给父进程,父进程的环境状态保持不变。直接执行(./)和调用解释器(sh/bash)均属于此类。
  • Source(当前进程执行):不创建新进程,直接在当前进程的上下文中解析并执行脚本代码。脚本内的所有操作等同于在当前命令行中逐行输入,因此环境的任何改变都会直接作用于当前进程。
  • Exec(进程替换):与 Source 类似,脚本在当前进程内执行,但 exec 会使用新的程序映像替换当前进程的内存空间。这意味着当前 Shell 进程将被脚本进程完全取代,脚本执行结束后,原 Shell 进程也随之终止,不会返回到原脚本的后续代码。

5. 实践验证:进程与环境的传递

我们可以通过以下两个脚本来直观观察 Fork、Source 和 Exec 在进程 ID(PID)和环境变量传递上的具体表现。

父脚本 (parent_script.sh):

#!/bin/bash
# 初始化环境变量并导出
STATE_VAR="initial_state"
export STATE_VAR

echo "=== [Parent] 执行前 ==="
echo "Parent PID: $$"
echo "Parent STATE_VAR: $STATE_VAR"

case "$1" in
    exec)
        echo "--- 触发 Exec 机制 ---"
        exec ./child_script.sh
        ;;
    source)
        echo "--- 触发 Source 机制 ---"
        source ./child_script.sh
        ;;
    *)
        echo "--- 触发 Fork 机制 (默认) ---"
        ./child_script.sh
        ;;
esac

echo "=== [Parent] 执行后 ==="
echo "Parent PID: $$"
echo "Parent STATE_VAR: $STATE_VAR"

子脚本 (child_script.sh):

#!/bin/bash
echo ">>> [Child] 执行中"
echo "Child PID: $$"
echo "Child 接收到的 STATE_VAR: $STATE_VAR"

# 修改环境变量
STATE_VAR="modified_state"
export STATE_VAR
echo "Child 修改后的 STATE_VAR: $STATE_VAR"

测试执行:

# 赋予执行权限
chmod +x parent_script.sh child_script.sh

# 测试 Fork 机制
./parent_script.sh fork

# 测试 Source 机制
./parent_script.sh source

# 测试 Exec 机制
./parent_script.sh exec

相关文章

Linux crontab 详解

1) crontab 是什么cron 是 Linux 的定时任务守护进程;crontab 是用来编辑/查看“按时间周期执行命令”的表(cron table)。常见两类:用户 crontab:每个用户一份(crontab -e 编辑)系统级 crontab / cron.d:可指定执行用户(/etc/crontab、/etc/cron.d/*)2) crontab 时间...

富文本里可以允许的 HTML 属性

一、所有标签默认允许的安全属性(极少)class        (可选)id           (通常建议禁用)title️ 注意:id 容易被滥用做锚点注入,很多系统直接禁用class 允许的话最好只允许固定前缀(如 editor-*)二、a 标签允许属性<a href="" t...

Mac 安装 Node.js 指南

方法一:通过官网安装包(最简单,适合初学者)如果你只是想快速安装并开始使用,这是最直接的方法。访问 Node.js 官网。页面会显示两个版本:LTS (Recommended For Most Users):长期支持版,最稳定。建议选这个。Current:最新特性版,包含最新功能但可能不够稳定。下载 .pkg 安装包并运行。按照安装向导点击“下一步”即可完成。方法二:使用 Homebrew 安装(...

Dom\HTML_NO_DEFAULT_NS 的副作用:自动加闭合标签

在使用Dom\HTMLDocument时,Dom\HTML_NO_DEFAULT_NS 将禁止在解析过程中设置元素的命名空间, 此设置是为了与DOMDocument向后兼容而存在的。当使用它时,已知的一个副作用就是:自动加闭合标签例如 </img> 为什么会这样?当你使用:Dom\HTML_NO_DEFAULT_NS文档会变成 无命名空间模式,此时内部更接近 XML...

Laravel 事件和监听器创建

在 Laravel 中,使用 Artisan 命令创建 Events(事件) 和 Listeners(监听器) 是非常高效的。你可以通过以下几种方式来实现:1. 手动创建单个 Event如果你只想创建一个事件类,可以使用 make:event 命令:Bashphp artisan make:event UserRegistered执行后,文件将生成在 app/Even...

自定义域名解析神器 dnsmasq

什么是 dnsmasq?dnsmasq 是一个轻量级、功能强大的网络服务工具,专为小型和中等规模网络设计。它是一个综合的网络基础设施解决方案[1]。dnsmasq 能做什么?功能说明应用场景DNS 转发与缓存将 DNS 查询转发到上游服务器(ISP、Google DNS 等),并在本地缓存结果加快 DNS 查询速度,减少外部 DNS 流量本地 DNS解析本地网络设备的主机名,无需编辑&n...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。