
1. 从一次“su 环境不听话”的排查说起.ksurc这个东西很多人第一次听说是在翻 KernelSU 的模块目录时看到一个不起眼的点文件躺在/data/adb/下面既没有扩展名说明也没有官方文档大书特书。我最初也把它当成一个可有可无的残留文件直到有一次在调试一个需要特定环境变量的 root 脚本时发现每次su进去之后PATH都被重置、自定义的LD_LIBRARY_PATH莫名其妙丢失、连umask都不是我想要的默认值才回过头来认真研究这个文件到底管什么。这篇内容就是围绕KernelSU 的.ksurc定制 su 启动环境展开的深度解析。它适合已经刷入 KernelSU、日常会用su执行脚本或调试的中阶用户也适合那些想搞清楚“为什么我的 root shell 环境和别人不一样”的折腾党。核心要解决的问题很具体如何让每一次通过 KernelSU 获得的 root shell都自动带上你想要的变量、别名、路径和工作目录而不是每次手动 export 一遍。关键词就三个KernelSU、.ksurc、su 启动环境。下面我会从机制、写法、踩坑、验证四个层面把它拆开讲透尽量做到你照着抄就能用。先说结论性的判断.ksurc本质上是 KernelSU 在拉起 root shell 时读取的一个启动脚本作用类似于桌面环境里的.bashrc或登录 shell 的 profile 文件但它生效的时机、作用范围、以及和系统原有 shell 配置的优先级关系跟普通的 rc 文件并不完全一样。理解这一点后面所有的定制才不会翻车。2..ksurc到底在 su 的哪个环节被读取2.1 一次 su 请求的完整生命周期要搞明白.ksurc为什么有时候生效、有时候不生效得先知道 KernelSU 处理一次su请求大致走了哪几步。我用一个简化的链路来描述方便你建立心智模型用户在终端或脚本里执行su这个请求被送到 KernelSU 的管理层管理层完成授权判断是否允许该 uid 提权、是否命中授权列表授权通过后KernelSU 准备一个 root 身份的 shell 进程在 shell 正式进入交互或执行命令之前它会去检查/data/adb/.ksurc是否存在如果存在且可读就把它作为启动脚本注入到当前 shell 的初始化流程里之后才是用户命令真正开始执行。关键点在第 4 步和第 5 步之间。.ksurc不是被“source 到你的交互 shell 里”这么简单它更像是被当作一段预置脚本在 shell 拿到控制权之前就跑完了。这意味着你在里面写的export、alias、cd这些操作会直接影响后续 shell 的初始状态但它的执行上下文和你手动敲命令的上下文未必完全一致——这一点是很多坑的根源。2.2 它和.bashrc、profile的优先级关系很多人会问我系统里已经有/etc/profile、用户目录下的.bashrc再搞一个.ksurc会不会打架实测下来的规律是这样的.ksurc的注入时机通常早于交互 shell 读取用户级 rc 文件如果你在.ksurc里设置的变量后续又被.bashrc里的同名变量覆盖那最终生效的是.bashrc的值反过来如果.bashrc里没有碰这个变量.ksurc的设置就会保留下来。所以正确的定位是.ksurc负责“root 环境的基础底座”.bashrc负责“交互层的个性化”。把那些“每次 su 都必须存在、且不希望被交互配置干扰”的东西放.ksurc比如基础PATH补全、必要的库路径、安全相关的umask把纯交互的别名、提示符美化放.bashrc。两者分工明确就不会互相踩。提示不要试图在.ksurc里做太重的操作比如启动后台服务、挂载文件系统。它的执行窗口很短重操作容易拖慢每一次 su 的响应甚至在某些机型上导致 shell 初始化超时。2.3 为什么它放在/data/adb/而不是/system或用户目录这个路径选择其实很有讲究。/data/adb/是 KernelSU 相关持久化数据的聚集地特点是可写、重启保留、且不随系统分区只读限制。放在这里你不需要重新挂载 system 分区就能改改完下一次 su 立即生效非常适合频繁调试。相比之下如果你把配置写进/system/etc之类的地方不仅要处理只读挂载还可能因为系统更新被覆盖。另一个隐含好处是权限边界清晰。/data/adb/本身对普通应用不可见.ksurc放在这里天然就带了一层隔离不用担心被随意读取。这也是为什么我建议你不要把这个文件挪到/sdcard下再软链过来——软链在某些 shell 初始化阶段解析时机不对容易读不到。3. 写一份能用的.ksurc从最小可用到进阶定制3.1 最小可用骨架与文件权限先给一个我日常用的最小骨架你可以直接照着建# /data/adb/.ksurc export PATH/data/adb/ksu/bin:/system/bin:/system/xbin:$PATH export HOME/data/adb umask 022三行分别解决三件事补全 KernelSU 自己的工具目录到PATH、把 root 的HOME指到一个可写且持久的位置、设定一个合理的默认umask。别小看这三行很多“命令找不到”“配置文件写到奇怪地方”“新建文件权限诡异”的问题根源都在这。创建和赋权建议这样操作su -c touch /data/adb/.ksurc su -c chmod 644 /data/adb/.ksurc su -c chown root:root /data/adb/.ksurc权限给644就够了属主 root。有人喜欢给600理论上更严但要注意某些注入路径下如果读取身份不是纯 root600可能导致读不到实测644兼容性最好。改完之后不需要重启下一次新开 su 会话就会读取。3.2 环境变量定制的取舍逻辑环境变量是.ksurc最核心的用途但不是什么变量都往里塞。我的取舍原则是只放“跨会话必须一致、且不希望被交互配置污染”的变量。举几个典型变量是否建议放.ksurc理由PATH建议保证基础命令可寻址避免每次手动补HOME建议决定配置文件落点必须稳定LD_LIBRARY_PATH谨慎放错顺序会导致系统库被自定义库顶掉引发崩溃TMPDIR建议指向可写目录避免临时文件写到只读分区PS1不建议纯交互美化放.bashrc更合适LANG视情况影响脚本输出编码需要统一时可放LD_LIBRARY_PATH那一行我要特别强调如果你确实需要它一定要把系统库路径放在自定义路径之后也就是让系统库优先命中。顺序写反了轻则某个命令行为异常重则 shell 直接起不来表现为 su 之后黑屏或立即退出。我踩过这个坑排查了半天才发现是库路径顺序问题。3.3 别名与函数的边界能放但别贪.ksurc里写alias和 shell 函数是可行的但我建议克制。原因是别名只在交互式 shell 里才有意义而.ksurc的注入上下文未必是交互式的——如果你在脚本里调用su -c xxx别名根本不生效。所以纯交互用的别名比如alias llls -al放.bashrc需要在非交互场景也生效的逻辑写成函数或独立脚本并在.ksurc里确保其所在目录在PATH中。一个实用技巧是把常用的一批 root 操作封装成脚本放到/data/adb/ksu/bin/下.ksurc只负责把这个目录加进PATH。这样无论交互还是脚本调用都能直接敲命令名比别名可靠得多。3.4 工作目录与 umask 的隐性影响cd到某个目录这件事在.ksurc里要慎用。因为如果目标目录在某些场景下不存在比如外置存储还没挂载cd失败可能导致后续脚本中断。稳妥写法是加判断[ -d /data/adb/workspace ] cd /data/adb/workspaceumask则是个容易被忽视但影响深远的设置。默认022意味着新建文件是644、目录是755对 root 场景通常够用。如果你在做一些需要更严格权限的调试可以设077但要注意这会让某些依赖组权限的工具行为异常。改umask之前先想清楚你后续要创建什么类型的文件。4. 那些让我返工三次的坑4.1 语法错误导致 su 静默失败最坑的一类问题是.ksurc里写了语法错误结果不是报错而是su 直接静默失败或者行为异常。因为注入阶段没有友好的错误提示你只会看到“su 之后什么都没发生”或者“shell 秒退”。我的排查套路是先用su -c echo ok测试基础提权是否正常如果异常临时把.ksurc改名mv .ksurc .ksurc.bak再测一次如果改名后恢复正常基本锁定是.ksurc内容问题用sh -n /data/adb/.ksurc做语法检查能揪出大部分括号、引号不匹配。这个“改名对照法”是我排查此类问题最快的手段比逐行注释高效得多。4.2 变量展开时机与引号陷阱.ksurc里写export FOO$BAR时$BAR的展开发生在注入执行的那一刻而不是你后续使用的那一刻。如果BAR在注入时还没定义FOO就是空值。更隐蔽的是引号问题# 危险写法路径含空格时会被拆开 export MYDIR/data/adb/my folder # 正确写法 export MYDIR/data/adb/my folder路径里带空格在 Android 上不算常见但一旦出现不加引号就会导致变量被截断后续所有依赖它的操作全部错位。养成给路径变量加引号的习惯能省掉大量莫名其妙的 bug。4.3 覆盖了不该覆盖的 PATH我见过有人为了“让某个工具优先”在.ksurc里写export PATH/my/tool:$PATH结果把自定义目录放到了系统目录前面导致系统自带的同名命令被顶掉行为完全变样。正确做法是明确知道自己在覆盖什么要么把自定义目录放后面要么用绝对路径调用不要盲目前置。PATH 的顺序就是命令解析的优先级改它等于改整个 shell 的命令语义。4.4 修改后“不生效”的三种真实原因改完.ksurc发现没变化先别怀疑人生按这个顺序排查旧会话未退出已经开着的 su shell 不会重新读取必须退出重进被后续 rc 覆盖检查.bashrc或系统 profile 是否又改了同名变量文件编码或换行问题从电脑复制过来的文件如果带 BOM 或 CRLF 换行注入时可能解析异常用dos2unix或编辑器转成 LF。这三种我全踩过尤其是第三种肉眼完全看不出来只有用file或十六进制查看才发现行尾是\r\n。5. 验证与回滚让每次改动都可控5.1 一套五分钟的验证清单每次改完.ksurc我固定跑这套检查确认没有引入回归su -c echo $PATH su -c echo $HOME su -c umask su -c command -v 你自定义的命令四条命令分别验证路径、家目录、权限掩码、自定义命令可达性。全部符合预期才算这次改动合格。如果哪条不对回到上一节对照排查。这套清单的价值在于把“感觉能用”变成“确认能用”避免带着隐患继续往下折腾。5.2 保留一份可回滚的备份.ksurc出问题时最怕的是“改坏了又记不清原来写了啥”。我的习惯是每次大改前先备份su -c cp /data/adb/.ksurc /data/adb/.ksurc.bak出问题直接cp回来十秒恢复。备份文件放在同目录即可注意别让备份文件本身被误读——它没有.ksurc这个精确名字不会被注入流程命中安全。5.3 用独立脚本承载复杂逻辑当定制逻辑超过十几行我强烈建议把主体逻辑抽到一个独立脚本比如/data/adb/ksu/bin/init-env.sh.ksurc里只留一行调用[ -f /data/adb/ksu/bin/init-env.sh ] . /data/adb/ksu/bin/init-env.sh好处有三独立脚本可以单独做语法检查和单元测试.ksurc保持极简降低注入阶段出错概率逻辑复用方便别的场景也能 source 同一份脚本。这是我从“把所有东西堆进.ksurc”转向“分层管理”之后最大的收益。6. 把 su 环境当成一份可维护的配置来对待折腾.ksurc这段时间我最大的体会是root shell 的环境不该是每次临时拼凑的而应该是一份有版本、有备份、有验证的配置。很多人把环境变量当成随手 export 的一次性操作结果换个会话就丢脚本时灵时不灵排查成本极高。把.ksurc用好本质上是把这份“隐性知识”固化下来让每一次 su 都从一个确定的状态出发。几个我长期坚持的习惯分享给你改动前备份、改动后跑验证清单、复杂逻辑抽独立脚本、PATH 和库路径的顺序永远多想一步。这几条不复杂但能挡掉绝大多数返工。至于更进阶的玩法比如按不同授权身份加载不同的环境片段可以在独立脚本里根据$UID做分支思路是一样的——先保证底座稳定再谈个性化。