/proc/cmdline是内核启动时接收的原始命令行参数,只读且不可修改,真实反映本次启动实际传递的参数,不依赖配置文件或shell解析,是唯一权威来源。

直接看 /proc/cmdline 就是最准、最轻量的方式,它不依赖任何命令行工具,也不受 shell 解析干扰,是唯一反映“内核真正收到什么”的权威来源。
为什么 cat /proc/cmdline 是唯一可信的启动参数来源
所有 GRUB 配置(如 /etc/default/grub 中的 GRUB_CMDLINE_LINUX_DEFAULT)只是“写入配置”,最终是否生效,取决于更新 GRUB 后重启时是否成功传递给了内核。/proc/cmdline 是内核自己记录下来的原始字符串,连空格和等号都原样保留,不会被 shell 展开或转义污染。
常见误判场景:
- 改了
/etc/default/grub但没运行update-grub→/proc/cmdline不变 - GRUB 菜单里手动编辑了启动项(比如加了
init=/bin/bash)→/proc/cmdline会立刻体现,但配置文件里没有 - 某些嵌入式平台(如 STM32MP2)用 U-Boot 传参 →
/proc/cmdline是唯一能确认实际传入内容的地方
cat /proc/cmdline 输出格式与常见参数含义
输出是一整行空格分隔的键值对,例如:
root=PARTUUID=491f6117-415d-4f53-88c9-6e0de54deac6 rootwait rw earlyprintk earlycon loglevel=3 console=ttySTM0,115200
关键点:
-
root=必须存在,指定根设备;支持/dev/sda1、PARTUUID=...、UUID=...等形式 -
ro/rw控制根文件系统挂载模式;若没显式写,默认是ro(只读),后续由 init 系统 remount -
console=可出现多次(如console=tty0 console=ttyS0,115200),内核按顺序尝试输出 -
net.ifnames=0和biosdevname=0常一起出现,用于禁用新式网卡命名 -
selinux=0、systemd.unit=multi-user.target这类参数直接影响运行时行为,不能仅靠配置文件推断
如何安全提取某个参数值(脚本中常用)
别用 grep -oP 'param=\K[^ ]+' 这类正则——它在参数值含等号或空格时会崩(比如 systemd.log_level=debug 后面跟 systemd.log_target=kmsg,\K[^ ]+ 会截断)。
更鲁棒的做法是用 shell 内置解析:
cmdline=$(cat /proc/cmdline) root_dev=$(echo "$cmdline" | tr ' ' '\n' | grep '^root=' | cut -d= -f2-)
说明:
-
tr ' ' '\n'把整行拆成每行一个参数,避免空格干扰 -
grep '^root='确保匹配的是完整参数名开头,不是子串(比如防myroot=误匹配) -
cut -d= -f2-从第一个等号后取全部,兼容值中含等号的情况(如systemd.log_level=debug)
和 sysctl 查内核参数的根本区别在哪
/proc/cmdline 和 sysctl 完全不是一回事:
-
/proc/cmdline是「启动那一刻内核收到的指令」,只读,不可修改,生命周期仅限本次 boot -
sysctl操作的是/proc/sys/下的运行时可调参数(如net.ipv4.ip_forward),有些可热更新,有些只读,有些甚至重启后还原 - 混淆典型错误:
cat /proc/cmdline | grep ip_forward永远为空——因为ip_forward是运行时参数,不是启动参数
真正容易被忽略的是:很多运维以为改了 /etc/sysctl.conf 就等于“系统启动参数已设”,其实那是两套机制。启动参数决定“系统怎么起来”,sysctl 决定“起来之后怎么跑”。两者交集极少(比如 init= 和 systemd 的关系),不能互相替代。


















