news 2026/10/2 18:30:59

从su到sudo:Linux权限管理与sudoers配置实战指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
从su到sudo:Linux权限管理与sudoers配置实战指南

这两年我接手过的服务器和开发机,几乎每一台都会遇到"权限之问"——为什么su切不过去?为什么sudo报错说我不在sudoers文件里?为什么同样的命令在这台机器上能跑、在那台就卡住?大部分问题的根源,其实都落在su和sudo这两个看似简单的命令上。这篇内容我打算把这些年在Debian系、Termux甚至macOS上折腾su/sudo的经验全部捋一遍,把报错、配置、安全边界和实战修复一次性讲透。

1. su 和 sudo 的底层逻辑差异:为什么一个够用,一个总出事

1.1 先搞清楚su的"切换"到底是什么

su是"switch user"的缩写,最经典的用法就是su - root,或者不带横杠直接su root。它的底层逻辑很直接:当前终端会话从一个用户身份切换到另一个用户身份。如果目标用户是root,那你就是在提权;如果目标用户是别的普通账号,那就是在切换身份。

这里的"切换"是整套登录过程的复刻——加载目标用户的环境变量、Home目录、shell配置。所以你会发现,su - root和su root虽然表面都在切root,但效果差别不小:

  • su - root:完全模拟root登录,环境变量、当前目录、PATH全部按root的配置重新加载。
  • su root:保留当前用户的环境变量,只是把UID/EUID换成了root的。

这就引出一个非常经典的坑:你用普通用户执行su root切到root后,如果PATH还是普通用户的,那很多root专属命令可能找不到,比如/usr/sbin下的工具。我见过不少人切过去之后一脸懵地问我"为什么我的root没有ifconfig",其实就是没加横杠。

在传统的UNIX设计里,su提权的认证方式很简单——它要求你输入目标用户的密码。也就是说,你切root就得知道root的密码,你切alice就得知道alice的密码。

1.2 sudo的设计思路:不切换身份,只授权命令

sudo的全称是"superuser do",但它和其他提权工具最大的不同在于:它不是把整个会话切到root,而是在需要时,以root权限执行单条命令。

这个设计带来的实际体感差别非常大:

  • sudo验证的是当前用户自己的密码,不是root密码。
  • sudo权限受sudoers文件控制,你可以只给某个用户"执行apt"的权限,而不给他"修改shadow文件"的权限。
  • sudo执行完就退出root上下文,没有"滞留"在root会话里的风险。

换句话说,su是"进入一个房间,拿到钥匙,之后所有操作都是主人身份";sudo是"每做一件事都要刷卡,但每张卡上写明了你能做哪几件事"。这种设计直接呼应了现代系统的安全基线:最小权限原则。

1.3 为什么现代系统默认推荐sudo而不是su

我在生产服务器上几乎不用su,原因有三条:

  1. 你一旦su - root切过去,终端上所有命令都是root身份执行,哪怕你只是想看一下日志,手滑输了个rm -rf ./*,整个目录都可能没了。sudo则强迫你明确"这条命令需要特权",误操作概率小很多。
  2. su一旦把root密码泄露给某个同事,对方可以随时切root,审计日志里什么都查不出来。sudo则每一条命令都会记录在/var/log/auth.log或journalctl里,出了问题能追溯到人。
  3. su依赖root密码存在且可靠,而现代Linux发行版(尤其是Debian系)默认甚至不设置root密码,安装过程中让你设的那个密码其实是第一个普通用户的密码,root账号默认锁定。你用passwd root设置root密码之前,su - root根本没有成功路径。

2. sudoers 配置:从"未出现在 sudoers 文件中"到精细化授权

2.1 最常见的报错:a 未出现在 sudoers 文件中

这条报错的中文原文是a 未出现在 sudoers 文件中。此事件已被记录。对应的英文是a is not in the sudoers file. This incident will be reported.。

我见过很多新手第一次遇到这行字,第一反应是"我被系统拉黑了吗"。其实本质上就是一句话:你这台机器上,当前用户没有被授予任何sudo权限。系统不仅拒绝你,还会把这个尝试记录到认证日志里——这就是"此事件已被记录"的意思。

摸排思路是这样的:

  • 先确认当前用户是谁:whoami、id。
  • 再看这台机器上的sudo权限是配给哪个组的:Debian/Ubuntu是sudo组,RHEL系的CentOS是wheel组。
  • 最后看当前用户在不在这几个组里:groups命令直接看。

如果你确定这个用户需要sudo,那就得用有sudo权限的管理员或root去执行:

# Debian/Ubuntu系 usermod -aG sudo a # RHEL/CentOS系 usermod -aG wheel a

注意-aG里的-a(append)是"追加"的意思,这是必须的。如果你漏了-a,那usermod -G sudo a会把用户从其他所有组里踢出来,尤其是从某些关键组踢出去之后,用户可能直接登不进来。这个坑我踩过一次,所以现在我写usermod都会下意识确认-a有没有跟上。

改完组之后,让用户重新登录(或者执行newgrp sudo),再执行sudo -l看看授权情况。

2.2 用visudo而不是直接vim编辑sudoers

热搜词里有sudo vim,这个操作本身没错,但很多人会把sudo vim /etc/sudoers当成常规编辑方式。这里我一定要强调:别动/etc/sudoers的歪脑筋,即使是用sudo也不行。

正确做法是执行:

sudo visudo

visudo的核心价值不是"打开编辑器",而是语法校验。它会先把你编辑的内容保存到一个临时文件,在覆盖正式文件前执行visudo -c做语法检查。一旦语法错了,比如少了个逗号、多了一个空格、别名写错,visudo会拒绝保存,从根源上避免你把sudoers写坏、导致所有人都无法sudo的惨剧。

如果你哪天手痒直接vim /etc/sudoers,把文件改坏了,而且坏到连sudo都跑不起来,而你又没有root密码——那重启后你会发现自己彻底被锁在门外。碰到这种情况,唯一的自救路径通常是重启进入单用户模式(recovery mode)去修复。所以,visudo这个习惯不是锦上添花,而是保命的。

2.3 给用户开白名单:从"什么都能干"到"只允许干这几件事"

sudoers文件的结构,我建议新手先理解核心的两行格式:

用户名 主机列表 = (可切换身份) 命令列表 %组名 主机列表 = (可切换身份) 命令列表

比如:

a ALL=(ALL:ALL) ALL

这一行表示:用户a,从任何主机(第一个ALL)连接,可以以任何用户身份(括号里的ALL),执行任何命令(最后的ALL)。这个就是典型的"全量sudo"。

但如果你想让a只能管理包管理器,可以写成:

a ALL=(root) /usr/bin/apt, /usr/bin/apt-get

这样a就只能sudo执行apt和apt-get,sudo vim /etc/shadow这种操作会被直接拒绝。命令白名单的价值在于:既给了用户工作所需的权限,又限制了出错或恶意操作的范围。

再进一步,如果想免密码执行特定命令,加上NOPASSWD:

a ALL=(root) NOPASSWD: /usr/bin/apt, /usr/bin/apt-get

但NOPASSWD要慎用。我在CI/CD脚本或自动化任务里会用,因为无人值守场景确实没法交互输密码;但在日常开发机上,我建议保留密码验证,多一层确认就多一道保险。

2.4 检查授权状态:sudo -l 是最好的体检工具

配置完之后,最快验证方式不是直接跑一条sudo命令,而是执行:

sudo -l

它会列出当前用户在sudoers里被赋予的全部权限,包括可以跑哪些命令、是否可以NOPASSWD、可以切换成哪些身份。我每次改完sudoers,都会先sudo -l确认格式和权限符合预期,再实际跑一条命令做二次确认。

这里有个细节要注意:如果你的用户同时存在于%sudo ALL=(ALL:ALL) ALL和更具体的白名单规则里,sudoers采用"last match wins"(后匹配生效)的策略。所以规则顺序会影响最终结果,配置的时候最好把更严格的规则放在后面,覆盖前面的宽泛规则。

3. 实操中高频翻车的报错排查:令牌错误、密码不认与权限越界

3.1 su: 鉴定令牌操作错误——不一定是密码错了

热搜词里有一条很典型:设置root密码时su:鉴定令牌操作错误。这条中文报错对应的英文是su: Authentication token manipulation error,很多人一看"鉴定令牌"四个字就懵了,以为是自己输错密码。

我排查这类问题的时候,第一反应不是密码,而是tty(终端设备)的可用性。su在验证密码时需要读取终端设备,如果当前会话没有正常的tty(比如在脚本里、在某些容器环境里、或者通过某些远程执行方式调用su),它就会尝试直接操作认证令牌,触发这个错误。

另一个高频原因是:你在执行su之前,先执行了passwd root但没成功设置密码。比如在Debian默认root密码为空/锁定的状态下,你直接su - root,系统发现root账号处于不可认证状态,也会抛出类似的令牌错误。

处理路径分两步:

  1. 先确保真的给root设过密码。执行sudo passwd root,按提示输入两次新密码。如果这一步报错,要先解决sudo权限问题。
  2. 确保你有正常的tty。直接在ssh登录的终端里执行su -,不要在sh -c "su - root -c '...'"这种嵌套环境里执行。

如果你只是想在脚本里提权,我会直接改用sudo而不是su,因为sudo不依赖目标账号密码,也不需要完美的tty绑定,对自动化更友好。

3.2 密码输入正确但sudo就是报错:不在sudoers中的陷阱

热搜词里还有一条典型的:sudo apt update [sudo] a 的密码: a 未出现在 sudoers 文件中。注意一个关键细节——它是让你输入了密码之后才报的"不在sudoers中"。这就让很多人困惑:"密码都对了,为什么还不让我用sudo?"

这里的逻辑其实很清晰:sudo的密码验证只是确认"你是你"(认证阶段),但"你有没有资格执行sudo"是另一回事(授权阶段)。认证通过不等于授权通过。所以你输对了密码,系统照样会因为你在sudoers里没有任何规则而拒绝。

这种情况的排查链路我固定走三步:

  1. 执行getent group sudo看sudo组里到底有没有当前用户。
  2. 执行sudo -l -U 用户名看该用户在sudoers里的规则。
  3. 如果确实没有,按上文usermod -aG sudo 用户名去补上。

在Debian/Ubuntu上,sudo组成员是开箱即用的。其他发行版要注意:有的用的是wheel组,有的默认连sudo包都没装。如果你执行sudo显示command not found,先apt install sudo或yum install sudo,再谈授权。

3.3 sudo powermetrics 在macOS上为什么会失败

热搜词里有一条比较特殊:sudo powermetrics --samplers smc失败。这属于macOS平台的问题,和Linux的sudo机制没有直接关系,但很多人会把这两者混在一起排查,所以单独提一下。

powermetrics是macOS上一个需要root权限读取电源管理数据的工具,--samplers smc会去读SMC(系统管理控制器)的数据。失败的原因通常是:

  • 当前Mac的SMC数据在某些型号/系统版本上不允许普通root会话直接读取。
  • SIP(系统完整性保护)限制了部分底层硬件的访问。
  • 缺少必要的权限属性,需要额外授予终端App"完全磁盘访问权限"或开发者模式权限。

处理这个问题的思路,是先在一般sudo命令上验证root权限是否正常(比如sudo whoami应该输出root),再确认powermetrics工具的路径和帮助信息:

sudo /usr/bin/powermetrics --help

如果连help都跑不了,那大概率是工具路径或SIP问题,不是sudo配置问题。如果help能跑,那就换个sampler参数试试,比如sudo powermetrics --samplers cpu_power。这类跨平台的特权问题,我的经验是:先把"sudo本身好用"和"目标程序能不能跑"两件事分开验证,别黏在一起猜。

4. 跨平台使用差异:Debian系、Termux、macOS 的 su/sudo 行为对比

4.1 Debian系默认没有root密码,直接su必吃闭门羹

前面提过,Debian/Ubuntu安装过程中设置的密码是第一个用户(在sudo组里)的密码,而不是root密码。root账号默认是锁定的,密码位是!,表示不可登录。

所以在纯Debian/Ubuntu环境里:

su - root

要么提示认证失败,要么提示令牌错误。这不是说你记错了密码,而是root密码压根没设置。

这种设计背后的逻辑很安全:既然管理操作都能通过sudo完成,那root密码就是不必要的高风险资产。也正因如此,Debian系用户的常规提权路径就是sudo -i或sudo -s:

  • sudo -i:模拟root登录,加载root环境变量。
  • sudo -s:以root身份启动shell,但保留当前用户环境变量。

这两个命令既是su的替代品,也比su更安全,因为它们仍然受sudoers控制。

如果你想纯粹复刻"su到root"的体验,可以设置root密码:

sudo passwd root

但我的建议是:除非有特殊原因(比如需要直接ssh登录root),否则不要开root密码。你一旦给它设置了密码,相当于给服务器多开了一个超级入口,而这个入口通常会比sudo更暴力、更难审计。

4.2 Termux里的su:从"Android沙箱"到"root手机"

热搜词里有一条termux如何从su模式退出,可以看出很多人在Termux环境里遇到了su的困惑。

Termux是Android上的终端模拟器,它的用户态和Linux发行版不太一样。你在Termux里执行su,正常情况下会尝试调用Android系统的root授权工具(比如Magisk)。如果你的手机没root,su会直接报错或提示permission denied。如果你的手机已经root,su会授予Termux一个root shell。

从su模式退出,就是输入:

exit

因为su的本质是"开启一个子shell",退出这个子shell就能回到原来的Termux普通用户shell。这个exit行为和Linux终端里的su完全一致。你也可以按Ctrl+D(EOF)来退出当前shell。

有人会问:为什么我在Termux里su之后,命令提示符怎么不变?这取决于su的实现。Magisk的su在root后可能会把shell切换到root,但Termux的shell环境变量没变,提示符看起来类似。我建议用id或whoami来确认身份,而不是靠提示符判断。

这里必须提一句:Android的root是一个危险操作,Termux的su只是把手机上已有的root能力暴露给shell,它不会帮你root手机,也不应该成为你获取root的方式。对绝大多数Termux用户来说,不root手机也能完成大量开发、服务器管理、Python脚本等任务,没必要第一步就去碰root。

4.3 macOS上的sudo与root启用逻辑

macOS可以说和Debian系走了一个路线:默认不建议你直接启用root用户。系统偏好设置里有个"访达 > 实用工具 > 目录实用工具",可以打开root用户,但这需要你先用sudo执行dscl命令来设置root密码。

在macOS上日常提权就是一句话:要权限就sudo,不要把root当日常账号用。macOS的sudo默认配置也存在/etc/sudoers,不过它管理的用户和组更偏向于admin组。你在Mac上安装软件时弹窗输入密码,背后走的很大概率就是sudo或它的GUI等价物。

有意思的是,macOS的sudo对"命令是否存在"很敏感。因为默认的secure_path会限制PATH,只包含系统目录。如果你用Homebrew装了工具(路径通常在/opt/homebrew/bin),直接sudo brew install xxx可能会报brew: command not found。

这是因为sudo执行时会把PATH重置为安全路径,排除了Homebrew目录。解决办法是先找到brew的真实路径,再让sudo用它:

sudo /opt/homebrew/bin/brew install xxx

或者修改sudoers里的secure_path。我个人更推荐前者,改sudoers的风险总是大于直接写绝对路径。

5. 修复数据目录权限的典型案例:sudo chown -r 1000:1000 ./data

5.1 为什么Docker卷的权限老是乱

热搜词里有一条sudo chown -r 1000:1000 ./data,这其实是个非常典型的容器卷权限修复操作。问题场景通常是这样的:

Docker容器里的进程以UID 1000运行(很多镜像默认的非root用户就是1000),但你在宿主机上把这个目录挂载出来的所有者是root(UID 0)。容器内进程写文件时,可能因为目录权限拒绝写入,或者写入后宿主机上看到的文件属于root,你普通用户根本删不掉。

这个问题的根源是:UID/GID是数字层面的身份标识,容器内外共享同一个内核的UID命名空间(默认情况下)。容器里的UID 1000,在宿主机上就是UID 1000。如果宿主机上UID 1000不是一个用户(很多宿主机第一个用户就是1000,但也不一定),你就会看到一堆"数字用户"的文件。

5.2 用sudo chown把目录归属对齐

修复方式很直接:把宿主机目录的所有权改成容器进程所使用的UID/GID。假设容器里进程的用户UID是1000、组GID是1000,宿主机当前登录用户叫a:

sudo chown -R 1000:1000 ./data

注意-R表示递归,会把./data下的所有文件、子目录全部改掉。这一步需要root权限,因为修改文件所有者不是普通用户的权限范围,所以前面必须加sudo。

如果你希望宿主机上的用户a能直接读写这些文件,可以把1000:1000改成a:a或者用a:staff。但这里有一个关键考量:容器内进程的UID必须和宿主机文件的所有者UID一致,否则容器内写入的文件在宿主机上仍可能权限错乱。所以,你该改的是目录所有权,而不是一厢情愿地只迎合宿主机用户。

更稳妥的验证方式:

ls -ld ./data id 1000 2>/dev/null || echo "UID 1000 doesn't exist on host"

如果宿主机上根本没有UID 1000对应的用户名,ls -ld会显示数字。你不用慌,数字本身也能工作——容器看的是UID,不是用户名。

5.3 chown之后还要注意的事

sudo chown -R虽然简单,但有几个容易忽略的细节:

  1. 符号链接:chown -R默认会跟随目录符号链接,这可能把你没想改的目标目录也改掉。如果数据目录里有符号链接指向别处,建议先用find ./data -type l -exec chown -h ...单独处理链接,或者确认链接目标也在预期范围内。

  2. 文件属性: chown之后如果文件还是不能写,检查一下文件系统挂载参数,比如noexec、ro,以及SELinux上下文。在RHEL系上,SELinux的container_file_t标签可能比所有权更重要。

  3. 不要盲目把所有linux系统文件都chown: 有些人会用sudo chown -R 用户名 /usr这种命令来"解决权限问题",这会把整个系统打入万劫不复。系统文件的权限是按设计好的,你改掉之后,很多依赖SUID、s位、特定属主的程序会直接失效,连sudo都可能被玩坏。

如果你在容器编排环境里遇到这类问题,我还建议优先考虑修改容器镜像里进程的UID,或者在docker-compose.yml里用user: "1000:1000"指定容器运行用户,尽量让宿主机和容器从一开始就对齐,而不是反复chown。

6. 安全最佳实践:为什么现代系统默认推荐 sudo 而非 su

6.1 最小权限与审计:sudo是"留痕"的,su是"抹账"的

安全运维里有一句老话:没有审计的提权就是掩耳盗铃。

su切到root后,所有命令都算在root头上。系统日志里你根本分不清哪条是管理员A执行的、哪条是管理员B执行的。出了问题,大家面面相觑。

sudo则完全不同。每一条sudo执行都会在/var/log/auth.log(Debian系)或journalctl -u sudo(systemd环境)留下记录,包括时间、用户名、执行的命令、终端来源。哪怕你只是sudo -l,也会留下查询记录。这个审计能力在多人共管服务器、合规审计场景下几乎是刚需。

我实际遇到过一例:线上服务器被人执行了rm -rf /var/www/html,排查时就是靠auth.log里某条sudo rm -rf /var/www/html的记录定位到具体操作者和确切时间点。如果用su,这条记录就时光倒流也找不回来了。

6.2 sudo时间戳缓存与安全边界

sudo默认有一个"时间戳缓存"机制:一次输入密码后,5分钟内再执行sudo命令,不需要重新输密码(时间长度由sudoers里的timestamp_timeout控制,默认5分钟)。

这个机制提升了体验,但也引出一个安全边界问题:当你的终端停留在root授权状态时,如果有恶意程序或同终端上的其他人借用这个窗口,就能不输入密码执行sudo命令。

缓解手段有三层:

  1. 在sudoers里设置更短的timestamp_timeout,比如Defaults timestamp_timeout=1。
  2. 每次用完立刻执行sudo -k,清除时间戳缓存。我把sudo -k当成一个肌肉记忆,尤其在公共终端上操作完敏感命令后,必执行。
  3. 使用sudo -K(大写K)彻底清除缓存的同时还清空相关记录的ttky。

另外,sudo还有一个容易被忽略的特性:sudo在非交互式场景(比如CI脚本)里如果遇到需要密码的情况,会直接失败,因为它无法弹出密码提示。如果你要写无人值守脚本,要么配置NOPASSWD,要么用sudo -S从标准输入读取密码。但-S会把密码暴露在脚本或进程列表里,我一般避免使用。更推荐的是先在脚本里sudo -n true探测一下是否已有有效缓存,没有就尽早报错,而不是在管道中间卡住。

6.3 一套我自己在用的sudo安全基线

分享一个我在自用服务器和开发机上贯彻的sudo配置思路:

Defaults env_reset Defaults timestamp_timeout=5 Defaults passwd_timeout=1 Defaults logfile=/var/log/sudo.log # 只给管理员组成员全量sudo %admin ALL=(ALL:ALL) ALL # 个别用户只给特定命令 deploy ALL=(root) NOPASSWD: /usr/bin/systemctl restart myapp, /usr/bin/systemctl reload nginx
  • env_reset:每次sudo都重置环境变量,避免用户自定义的LD_PRELOAD等变量污染特权命令执行环境,防止经典的提权攻击手法。
  • timestamp_timeout=5:5分钟无操作就过期,不会一整个上午都处于免密sudo状态。
  • passwd_timeout=1:密码输入窗口1分钟,超过自动作废。
  • logfile=/var/log/sudo.log:把sudo记录到独立日志文件,方便集中查看,不依赖系统日志排版。

deploy那行是典型的CI/CD账号配置:只能重启指定应用服务、只能重载nginx,其他sudo操作一律拒绝甚至不需要输入密码。这样即使密钥泄露,攻击者能造成的破坏面也极小。

我见过很多团队把deploy账号直接加进sudo组,结果一台机器被攻破,攻击者立刻拥有半个系统的控制权。这种教训一次就够了——sudo的配置不是"能用就行",而是要按用户实际干活的清单来发权限。

7. 结尾:提权命令再多,安全习惯才是关键

写到这里,我想把自己这些年用下来最深的体会再强调一遍。su和sudo不是两个等价的"切root工具",它们代表的是两种完全不同的权限管理哲学。su是旧时代"一把钥匙开全部门"的思路,简洁但难以治理;sudo是当代"按需授权、全程留痕"的思路,繁琐却可控。

在我日常工作中,su只出现在少数"必须完整切换身份"的自动化场景里,比如crontab脚本里用su - appuser -c '...'把任务交给指定服务账号;而所有交互式操作、CI/CD脚本、需要临时提权的操作,我全部走sudo。同时,不论用哪个,我都会在事后习惯性地执行sudo -k清理缓存,把权限窗口压缩到最小。

如果你正在踩"不在sudoers中"、su令牌错误或者chown权限混乱的坑,希望你回头看看对应章节的排查链路,大概率能定位到原因。真正的高手并不是不用root,而是懂得怎么让root权限像一把受控的钥匙——只有该用的时候它才出现在你手里,用完便立刻收回。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/2 18:30:55

Spring Boot自习室预约系统:并发预约冲突控制与状态机设计实战

简介:这套基于Spring Boot框架的自习室管理与预约系统源码,适合计算机专业学生、初级Java开发者用于课程设计、毕业设计或熟悉典型Web项目开发流程。系统采用MVC分层架构,前台支持用户注册登录、自习室预约、座位与开放时段查看,后…

作者头像 李华
网站建设 2026/10/2 18:29:23

NISP一级题库doc高效备考:从文档处理到错题管理的完整攻略

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/2 18:29:12

基于YOLOv5的AI自瞄实现:从目标检测到鼠标平滑控制全解析

简介:这套基于YOLOv5的AI自瞄项目源自高分毕设/课设,面向人工智能、自动化、电子信息、物联网等专业学生及开发者,可作为毕业设计、课程设计、作业或入门进阶的完整参考。项目在原始YOLOv5基础上进行二次开发,保留原有目录结构&am…

作者头像 李华
网站建设 2026/10/2 18:27:27

Typora代码块优化指南:从样式到排坑一次讲透

从python输进去,到十行八行看不出毛病,一旦遇到长脚本、日志片段、带中文注释的配置文件,各种幺蛾子就全冒出来了:代码不换行、拷贝到公众号格式全乱、语言高亮失效、导出 PDF 黑色方块占满一页……这篇就把我这两年折腾 Typora 代…

作者头像 李华
网站建设 2026/10/2 18:26:26

图像预处理核心:resize与padding的选择逻辑与实战决策

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/2 18:25:25

3-RRR并联机器人运动学建模与MATLAB仿真

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华