首先,我们需要深入了解 Linux Shell 的登录模式(Login Shell vs. Non-login Shell)。
1. 为什么 adb shell 会使开发板的开机初始化配置不生效?
当你本地终端连接开发板时,通常有两种情况:
- 常规登录(Login Shell) :比如通过串口(Serial)或 SSH 登录。这时 Shell 会完整执行
/etc/profile→\rightarrow→~/.bash_profile。 - 非登录交互式 Shell(Non-login Shell) :很多版本的
adb shell行为属于这一类。它直接启动了一个 Shell 进程,但跳过了 全局的/etc/profile过程。
2. adb shell 登录后的常用操作
既然你已经通过 adb 进去了,这里有几个比串口调试更高效的操作:
- 文件传输 (不进 shell) :
adb push <电脑路径> <开发板路径>:把编译好的server_arm发送到板子。adb pull <开发板路径> <电脑路径>:把板子里的日志抓回电脑。
- 查看系统日志 :
dmesg:查看内核 log。logcat(如果板子运行的是 Android 或带有 logcat 服务):查看应用层 log。
利用adb shell进入开发板的非登录交互式 Shell后,可以利用bash或source /etc/profile 登录开发板。
在 Linux 开发中,source /etc/profile 是一个极其高频的命令,特别是在你配置交叉编译器路径或安装新的软件包之后。
简单来说,它的作用是:在当前终端会话中立即加载并执行 /etc/profile 文件中的配置,而无需重启终端或重新登录。
1. 命令拆解
source
- 功能 :这是一个 Shell 内建命令。它会读取指定文件中的内容,并在当前 Shell 进程中逐行执行。
- 别名 :在大多数 Shell(如 Bash)中,
source可以简写为一个点.。即. /etc/profile等同于source /etc/profile。 - 关键点 :如果不使用
source而直接运行/etc/profile(比如./etc/profile),系统会启动一个子 Shell 来执行。子 Shell 中设置的环境变量(如PATH)在执行完后会随子 Shell 的退出而消失,无法改变你当前使用的终端环境。
/etc/profile
- 身份 :这是 Linux 系统的全局配置文件。
- 范围 :它对系统内的所有用户都生效。
- 内容 :通常包含 export 语句(设置环境变量)、umask 设置、别名(alias)以及执行
/etc/profile.d/目录下的其他脚本。
2. 为什么在嵌入式开发中经常用到它?
当你修改了 /etc/profile(例如为了添加交叉编译器的路径)后:
- 修改文件 :你在文件末尾添加了
export PATH=$PATH:/home/book/toolchain/bin。 - 不生效的原因:Linux 只在用户登录时读取一次这个文件。你刚改完,当前的终端进程还不知道路径已经变了。
- 执行 source :运行
source /etc/profile后,当前终端会立即执行那行export命令。 - 结果 :现在你输入
arm-linux-gnueabihf-gcc -v就能找到编译器了。
3. 详细执行流程
当你执行该命令时,系统通常会按以下顺序"走一遍":
- 设置基础变量 :初始化
PATH、USER、HOSTNAME等。 - 调用路径脚本 :检查
/etc/profile.d/文件夹。- 该文件夹下有很多
.sh脚本(比如语言包设置、颜色设置)。 source命令会自动循环执行这些脚本,确保系统环境完整。
- 该文件夹下有很多
- 应用权限掩码 :设置
umask,决定新创建文件的默认权限。
4. source 与 重启终端 的区别
| 特性 | source /etc/profile | 重新打开终端 |
|---|---|---|
| 生效范围 | 仅限当前窗口 | 所有新开窗口 |
| 执行速度 | 瞬间完成 | 较慢 |
| 副作用 | 可能会导致环境变量重复叠加(如 PATH 里出现两个相同的路径) |
清洁的环境加载 |
💡 常见坑点提醒
- 权限问题 :虽然
/etc/profile是全局的,但你作为普通用户执行source是没问题的。只有在修改 它时才需要sudo。 - 永久生效 :
source只是让修改立即生效 。如果你发现每次开机都要source一下,那说明你并没有把配置正确地写进文件里,或者你写在了非启动加载的文件中。 - 重复执行 :如果你在脚本里多次
source,且脚本里有PATH=$PATH:/new/path,你的PATH变量会变得非常长。
利用bash或source /etc/profile 登录开发板是不同的逻辑,关乎到Linux 进程管理和 Shell 启动逻辑中一个非常细微的区别。
之所以 bash 和 source /etc/profile 看起来效果一样(都改变了命令提示符),是因为 100ask 的配置脚本里,把修改提示符的指令写在了 /etc/profile 中。
但是,它们在操作系统底层的行为是完全不同的:
1. 核心区别:嵌套 vs. 加载
bash 命令:创建了一个子进程
当你输入 bash 时,你是在当前的 sh 进程之上,又启动了一个全新的程序(Bash)。
- 结构 :这就像是"套娃"。
sh是父亲,bash是儿子。 - 效果:Bash 启动时会自动去读取配置文件(如果是登录模式),所以提示符变了。
- 为什么 exit 不一样 :当你输入
exit时,你只是杀掉了儿子(Bash) ,回到了**父亲(sh)**的怀抱。所以你得exit两次才能彻底退出adb shell。
source 命令:在当前进程中"吞噬"代码
当你输入 source /etc/profile 时,没有产生新进程。
- 结构 :你只是把
/etc/profile里的命令拿出来,直接在当前的sh里跑了一遍。 - 效果 :脚本里的指令修改了当前
sh的变量(比如PS1提示符),所以看起来变样了。 - 为什么 exit 不一样 :因为你一直就在这一个进程里。当你输入
exit时,你直接杀掉了当前的进程 ,于是adb连接断开,退回到了 Ubuntu。
2. 为什么提示符会变?
在 100ask 的 /etc/profile 文件中,通常有这样一行:
export PS1='[root@100ask:\w]# '
- 执行
bash时,Bash 启动并读取了这行,于是提示符变了。 - 执行
source时,当前的sh执行了这行,于是提示符也变了。
3. 深度对比表
| 操作 | 进程数量 | 内存关系 | exit 的行为 |
|---|---|---|---|
bash |
增加一个 | 子进程拥有独立空间 | 退出子进程,回到旧 Shell。 |
source |
保持不变 | 直接修改当前 Shell 变量 | 退出当前进程,彻底断开 adb。 |
4. 你的操作建议
既然你已经发现输入 bash 或者 source 都能获得你想要的编译环境:
- 如果你追求速度 :用
source /etc/profile,简单直接。 - 如果你追求功能的完整性 :用
bash。因为有些高级的 Shell 补全功能和快捷键只有在真正的 Bash 环境下才好用。
💡 小实验
你可以尝试输入 pstree(如果板子里有)或者 echo $$(查看当前进程 PID):
- 进入
adb shell,执行echo $$,记下数字。 - 输入
bash,再执行echo $$,你会发现数字变了。 - 输入
exit回到sh,执行echo $$,数字又变回来了。 - 执行
source /etc/profile,再执行echo $$,数字保持不变。
这就是"嵌套"与"加载"最直观的证据。