1. 为什么要把“账户和组管理”和“查找命令”放在一起聊
做Linux运维或者说日常跟服务器打交道,有两类命令是绕不开的。第一类是账户和组的管理命令,比如useradd、usermod、groupadd、id这一整套,它解决的是“系统里谁能用、能用什么权限”的问题;第二类是查找命令,比如find、locate、whereis、grep这套,它解决的是“文件到底放在哪、哪些文件占空间、哪些文件权限不对”的问题。
很多人学这两块是分开学的,但实际干活的时候它们经常混在一起用。举个例子:你发现某个服务启动异常,排查第一步要确认跑这个服务的用户是谁,然后要查这个用户对应的家目录和相关配置文件在哪,还要确认这个用户是不是属于某个特定的组,以及这个组有没有对某个路径的访问权限。这一套操作下来,账户管理和查找命令是交替上场的。
这篇内容适合刚入门Linux的运维新人,也适合那些已经会用几个命令但对底层逻辑不熟、经常踩坑的人。我会把账户和组管理这块从配置文件讲到命令实操,再把find命令的用法从基础语法拆到高级组合条件,最后补上一些我实际踩过的坑和排查技巧。整个内容我按照“先搞懂原理,再动手操作,最后总结经验”的顺序来写,保证你看完能直接上手用。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 账户和组管理:先把底层数据模型讲明白
2.1 账户信息到底存在哪
很多人刚开始学Linux的时候,习惯用useradd去加用户,但压根不明白这个命令到底在背后动了什么。其实Linux的账户管理本质上是维护四个文件:/etc/passwd存用户基本信息,/etc/shadow存密码哈希和密码策略,/etc/group存组信息,/etc/gshadow存组密码和组管理员信息。
先说/etc/passwd,每一行代表一个用户,用冒号分成7个字段。我来拆一个实际例子:
code复制devops:x:1001:1001:DevOps Engineer:/home/devops:/bin/bash
第一个字段是用户名devops;第二个字段是密码位,现在基本都是x,表示真正的密码哈希挪到了/etc/shadow里;第三个字段1001是用户ID(UID),第四个字段1001是主组ID(GID);第五个字段是备注信息,一般写用户全名或者职责描述;第六个字段是家目录路径;最后一个字段是登录Shell。
理解了这个文件结构,你就明白为什么说“手动创建用户”是可行的了。只要按照这个格式往/etc/passwd里追加一行,再创建对应的家目录、设置密码,这个用户就能用。当然,我建议你老老实实用命令,手工改文件容易出错,但理解结构能让你在排查问题时一眼看出问题在哪。
再看/etc/group,它的格式也是冒号分隔:
code复制devops:x:1001:zhangsan,lisi
第一个字段是组名,第二个字段是组密码位,第三个字段是GID,第四个字段是附加用户列表。注意,这个列表里只显示把该组作为辅助组的用户,主组关系不体现在这里,而是体现在/etc/passwd的第四个字段。
说句实话,我见过不少干了两年运维的人,居然不知道id命令可以一眼看出用户所有的主组和附加组关系。这个命令输出很重要:
bash复制$ id zhangsan
uid=1002(zhangsan) gid=1001(devops) groups=1001(devops),1002(zhangsan)
gid后面跟的是主组(也叫初始组),groups后面跟的是用户所属的所有组,其中第一个就是主组,其余的是附加组。这个区别很多人搞混,我后面讲组管理时会重点解释。
2.2 用户管理三件套:useradd、usermod、userdel
useradd是创建用户的核心命令,但我强烈建议你不要裸用,而是要配合参数使用,否则默认行为可能不符合你的预期。我实际工作中最常用的一套参数组合是:
bash复制useradd -u 1051 -g devops -G docker,nginx -c "Web Service Account" -d /data/webuser -s /sbin/nologin webuser
逐个解释一下:-u指定UID,这是为了统一管理,防止不同机器上的同名用户UID不一致,导致NFS共享目录的属主错乱;-g指定主组,-G指定附加组,这里webuser的主组是devops,同时附加到docker和nginx组,这样它就能用这两个组的权限;-c是注释,写清楚这个账户是干嘛的,方便后人维护;-d指定家目录,不一定非得是/home/用户名,有些业务账户的家目录放在数据盘更合理;-s指定Shell,像这种纯服务账户直接给/sbin/nologin,禁止登录,安全。
这里有个细节值得展开,-M参数表示不创建家目录,-m参数表示创建家目录,但默认情况下如果用-d指定了家目录,系统执行useradd时会自动创建这个目录并把目录所有权交给新用户。我遇到过有人加了-M又奇怪为什么家目录没生成,这是典型的参数理解偏差。
usermod用来修改已有用户属性,常用场景是改附加组、改家目录、改登录Shell。比如把用户zhangsan加到docker组:
bash复制usermod -aG docker zhangsan
注意这个-a参数,它的意思是append追加。如果你不加-a直接写usermod -G docker zhangsan,系统会把该用户原有的附加组全部清掉,只保留docker这一个组。这个坑我见人踩过不止一次,有个同事本想给用户加一个组权限,结果把用户从十几个组里踢出去了,业务直接报权限错误。
userdel删除用户,默认情况下userdel username只删除账户定义,不删除家目录和邮件池文件。想连家目录一起删,用userdel -r username。但这里我要提醒一句,生产环境删用户之前,最好先确认这个用户有没有运行中的进程或者遗留的文件,否则数据丢了找不回来。我删用户前通常先跑一句:
bash复制find / -user username -not -path "/proc/*" 2>/dev/null
先看看这个用户还拥有哪些文件,再决定怎么处理。
2.3 密码管理和账户锁定:passwd的几种打开方式
passwd是修改密码的命令,但它的功能不止改密码。常用玩法有这几种:
bash复制passwd zhangsan # 修改指定用户的密码,root可操作
passwd -l zhangsan # 锁定用户,禁止登录
passwd -u zhangsan # 解锁用户
passwd -S zhangsan # 查看用户密码状态
密码状态这里我详细说下,passwd -S的输出类似zhangsan P 2024-01-15 0 99999 7 -1,分别表示用户名、密码状态(P代表有密码可登录,L代表锁定,NP代表无密码)、最后一次修改日期、最小修改天数、最大有效天数、过期前几天提醒、禁用天数。如果你设置了密码策略,比如90天必须改一次密码,可以用:
bash复制chage -M 90 -m 7 -W 14 zhangsan
-M是最大有效天数,-m是最小修改间隔,-W是过期前几天开始提醒。等这个用户登录的时候,系统就会提示密码即将过期。我建议所有面向真实员工的账户都设置密码过期策略,而那些服务账户(/sbin/nologin的)不要设置过期,免得到期之后密码失效导致服务起不来。
有个很容易被忽略的细节是chage -d 0 username,这个命令把密码的最后修改时间改成“从未修改”,可以强制用户下次登录时必须先改密码。新创建的用户或者临时账号交付给同事之前,我都会执行一下这个操作。
3. 组管理:理解主组和附加组的本质区别
3.1 groupadd与groupmod的实际用法
组的创建和管理比用户简单,但有几个逻辑要理清。创建组:
bash复制groupadd -g 1051 devops
-g指定GID。如果你不在企业环境里做统一规划,GID让系统自动分配也可以,但一旦涉及跨服务器的文件共享和权限映射,GID就必须保持一致。我建议你在规划阶段就把整批服务器的用户和组清单整理出来,做成一个表统一分配UID和GID,后期会省很多麻烦。
groupmod用来改组名或者GID:
bash复制groupmod -n newgroup oldgroup # 改名
groupmod -g 2000 devops # 改GID
这里有一个必须注意的问题:如果你修改了一个已存在用户的主组GID,/etc/passwd里对应用户记录的GID并不会自动跟着变,你会发现用户的id输出里GID变成了不存在的组编号,显示为gid=1051(devops)的组名都没了。解决方法是改完组之后,需要手动同步修改相关用户的GID字段,或者干脆用usermod -g重新设置一遍主组。
3.2 主组与附加组:一个用户加多个组的正确姿势
主组是用户创建文件时默认的属组,附加组是用户额外获得权限的组。比如zhangsan的主组是devops,同时是docker组的附加成员,那么他创建的任何新文件属组都是devops,但他拥有docker组的访问权限。
给用户添加附加组,记住一句话:都用-aG,不要裸用-G。因为-G是“覆盖设置附加组列表”的语义,-aG才是“追加”。
删除用户的某个附加组稍微繁琐一点,因为usermod没有直接的“移除某个组”的参数。实际操作是将其余想保留的组重新列一遍:
bash复制usermod -G remaining_group1,remaining_group2 zhangsan
不带上-a,用完整的组列表覆盖原有的附加组列表。“保留除了docker之外的所有组”这种操作,先查id zhangsan输出,复制原有的groups列表,去掉不需要的组,再拼到-G后面执行。这活儿我干过很多次,每次都提醒自己再仔细核对一遍列表,别手滑把组删多了。
3.3 组密码与组管理员:Linux里被忽略的隐藏能力
gpasswd这个命令知道的人不多,但它能设置组密码和组管理员。组密码的作用是:当一个用户不属于某个组,但他想临时通过newgrp命令切换到该组身份时,需要输入组密码。组管理员则可以被授权来管理组成员,不必每次都找root。
设置组密码和管理员:
bash复制gpasswd devops # 设置组密码
gpasswd -A zhangsan devops # 指定zhangsan为devops组的管理员
gpasswd -a lisi devops # 把lisi加入devops组
gpasswd -d lisi devops # 把lisi从devops组移除
说实话,组密码这种机制在现在的生产环境里用得很少,多数人都是直接让root管理所有组。但如果你维护的是一个大型开发团队,多个项目组共用一个服务器,组管理员和组密码的能力就有价值了:你不需要把root密码分享给各组负责人,他们自己就能管理自己组的成员。这也是Linux权限模型里容易被忽视的一块。
4. find命令:不只是“找文件”那么简单
4.1 find的执行模型:逐目录遍历与表达式求值
很多教程一上来就摆参数,但我认为理解find的执行模型更重要。find命令本质上是“从指定路径开始,递归遍历每个目录和文件,逐个判断是否满足你给出的表达式条件,满足则执行动作”。默认动作是-print,也就是把匹配到的路径打印到标准输出。
理解这个模型对排查复杂问题很关键。比如你执行find / -name "*.log",系统是从根目录开始,进入每一个子目录,对每个文件做一次*.log的模式匹配。如果某些目录你没有读取权限,find会报Permission denied错误,你可以把标准错误重定向到/dev/null来忽略这些提示,但你要知道这会导致那个目录下的文件被跳过。
另一个重要概念是表达式的“从左到右短路求值”。find的条件之间用逻辑运算符连接,常见的三个运算符是-a(且,默认就是且)、-o(或)、-not(取反)。find会按从左到右的顺序判断,如果左边的条件是-false,右边的条件就不会执行了。这个特性在优化大目录查找时很有用。
4.2 按文件名、类型和路径查找:最常用的三个条件
按名字查找是最高频的操作:
bash复制find /data/logs -name "*.log"
find /data/logs -iname "*.LOG"
-name区分大小写,-iname不区分。如果你要匹配的文件名里有特殊符号,比如[、*、?,它们会被当作通配符处理,这点要格外小心。有一次我想找文件名带[test]的文件,直接写-name "[test]*"结果什么都没匹配到,因为[]被解释成了字符集匹配,[test]匹配的是t、e、s、t任意一个字符开头的文件名。解决方法是把整个文件名作为模式再包一层转义。
按类型查找:
bash复制find /data -type f # 普通文件
find /data -type d # 目录
find /data -type l # 符号链接
find /data -type s # socket文件
这个条件在清理环境时特别有用,比如你想找出某个目录下的所有符号链接,确认有没有失效的软链指向了被删除的目标。
按路径匹配:
bash复制find /data -path "*/2024/*" -name "*.log"
-path匹配的是整个路径字符串,不是只匹配文件名。这个配合-name使用可以达到“按目录层级过滤”的效果。
4.3 按大小和时间筛选:大文件清理的利器
查大文件是运维日常高频操作。我一般直接用:
bash复制find /data -type f -size +500M
-size的参数格式要记清楚:+500M表示大于500MB,-500M表示小于500MB,不带符号表示精确等于500MB。单位方面,小写k表示KB,大写M表示MB,G表示GB。还有个容易踩的坑:-size +5表示大于5个“512字节块”,不是5字节。如果只想用字节为单位,得写-size +1024c,其中c表示bytes。
按时间筛选这块,find提供了三个时间维度,分别是访问时间(atime)、修改时间(mtime)、状态改变时间(ctime)。最常用的是-mtime:
bash复制find /data/backup -type f -mtime +30
这个命令找到所有30天前修改过的文件,配合-delete或者-exec就能清理老备份。注意+30表示“大于30天”,也就是第31天及更早;-30表示“30天以内”;不带符号正好是30天整。如果你想按“分钟”级别找文件,用-mmin替换-mtime。
另外,-newer这个参数允许你拿一个参考文件的时间作为基准,比如:
bash复制find /data -type f -newer /tmp/ref_file
找出所有比/tmp/ref_file修改时间更新的文件。这个在排查“某个配置变更之后,到底哪些文件被改过了”的时候特别好用。
4.4 按权限和属主查找:安全巡检的必用条件
权限相关的查找条件有三个:-perm、-user、-group。先看基础用法:
bash复制find /data -user zhangsan
find /data -group devops
找出属于某用户或某组的文件。这个配合账户管理场景很实用,比如你要删除一个离职员工的账户,先用这两条命令找出他名下的所有文件,再决定归属权怎么处理。
按权限位查找是这个命令的进阶玩法。需要先理解-perm的三种模式:精确匹配、-权限匹配、/任意位匹配。我举个例子说明:
bash复制find /data -type f -perm 644
精确匹配,只找权限位正好是644的文件。
bash复制find /data -type f -perm -4000
-模式,它表示“指定权限位都必须满足”,这行命令会找出所有设置了setuid位的文件。setuid权限是权限位中的一个特殊位,它会让普通用户以文件属主的身份执行程序,常见的例子是/usr/bin/passwd。这类文件一旦被恶意修改,危害特别大,所以用-perm -4000做安全扫描是非常常用的场景。
bash复制find /data -type f -perm /222
/模式,表示“只要任意一个指定权限位满足就行”。上面这行会找出所有“其他用户可写”的文件,这类文件如果存在于系统目录里,会有被篡改的风险。
逻辑运算符组合一下,还能做更精确的匹配。比如找“属于zhangsan而且权限不是正常范围”的文件:
bash复制find /data -user zhangsan -type f \( -perm /022 \)
括号需要转义,这是find语法里容易忽略的点。
4.5 执行动作:-exec、-ok与xargs的取舍
find匹配到文件之后,经常要执行操作。删除操作用-delete最简单:
bash复制find /tmp -type f -name "*.tmp" -delete
但如果要做更复杂的操作,比如批量打包、批量改权限,就得用-exec了。看这个例子:
bash复制find /data/logs -type f -name "*.log" -mtime +7 -exec gzip {} \;
{}是find结果的占位符,\;表示-exec命令结束。这行的效果是把7天前的所有log文件逐个压缩。注意每个文件都会启动一次gzip进程,如果文件数量上千,这个方式的性能会比较差。更高效的做法是把文件列表一次性传给命令:
bash复制find /data/logs -type f -name "*.log" -mtime +7 | xargs gzip
xargs会把find输出的每行文件名作为参数,分批传给后面的命令。默认情况下,如果文件名中包含空格,xargs会把一个文件名拆成两段传给命令,这会出问题。解决办法是让find输出以\0结尾,同时告诉xargs也按\0分割:
bash复制find /data/logs -type f -name "*.log" -print0 | xargs -0 gzip
这个组合我强烈建议你养成肌肉记忆,凡是find和xargs连用,就带上-print0 | xargs -0,不会后悔的。
还有一个需要注意的操作是-ok,它和-exec的唯一区别是每次执行前都会问你y/n确认。对风险的批量删除操作,比如find /data -name "*.bak" -ok rm {} \;,我会先跑一次不带删除的纯查找,确认结果列表没问题,再换成-ok逐条确认,而不是直接-exec rm一把梭。
4.6 性能优化:从根目录全盘扫描要多久
很多人第一次用find是执行find / -name "xxx",然后等了几分钟都没出结果。这不是命令卡死,而是从根目录递归遍历整个文件系统本来就需要时间,尤其是在/proc、/sys这类虚拟文件系统上遍历还会产生大量无意义的IO。
两个优化方向。第一,明确查找范围。如果你知道目标文件大概率在/usr和/etc下,就别从/开始。第二,排除不必要的目录。用-prune参数可以跳过指定目录:
bash复制find / -path /proc -prune -o -path /sys -prune -o -name "*.conf" -print
这个命令的执行逻辑是:先判断当前路径是不是/proc,是就剪枝跳过目录内部,然后继续判断是不是/sys,接着再判断文件名是否匹配*.conf。注意-prune和-o搭配时,最后的-print要放在正确的位置,否则可能啥都不输出。
还有个实用技巧是利用-maxdepth限制递归深度。在明确知道目标文件就在三层以内的场景,加上这个参数能省大量时间:
bash复制find /data -maxdepth 3 -name "*.conf"
5. 其他查找命令和find的配合使用
5.1 which、whereis、locate与find的适用场景对比
find是实时遍历查找,优点是准确、条件多,缺点是慢。有些场景我们需要更快的方式,就可以用其他几个命令,我再整理一个对比表:
| 命令 | 查找方式 | 查找范围 | 典型场景 | 速度 |
|---|---|---|---|---|
which |
按PATH环境变量顺序查找 | 可执行命令 | 查ls、curl这些命令装在哪 | 极快 |
whereis |
从固定系统目录查找 | 二进制、源码、man手册 | 查某个服务的二进制和帮助文档位置 | 极快 |
locate |
查预建的数据库 | 全文件系统 | 快速找明确名字的文件 | 快,但可能滞后 |
find |
实时递归遍历 | 指定路径下 | 复杂条件、精确查找 | 看范围,一般较慢 |
which我不建议依赖,因为不同机器的PATH变量不一样,同一台机器如果用了不同的用户身份,PATH也可能不同。更可靠的是command -v,它是shell内置功能,比如command -v python3。而whereis本质上是在/bin、/sbin、/usr/bin等固定目录里查找,对自定义安装路径无能为力。
locate的关键弊端是索引不是实时的。系统默认每天更新一次数据库,新建的文件当天查询可能找不到。手动更新用updatedb,但如果没有权限或者数据库较大,也要等一段时间。
5.2 grep与find协同:把文件内容也纳入查找
find只能按文件名、属性这些元数据筛选,它看不到文件内容。要在“一堆文件里找包含指定文本的文件”,就得用grep。最经典的是递归搜索:
bash复制grep -r "error" /data/logs/
但把find和grep组合起来更灵活,尤其是可以先按条件缩小文件列表,再对列表里的文件做内容匹配:
bash复制find /data/logs -type f -name "*.log" -mtime -1 -exec grep -H "ERROR" {} \;
我解释下这个命令干了什么:先在/data/logs下找到最近一天内修改过的所有.log文件,然后对每个文件执行grep -H "ERROR",找出包含ERROR关键字的行,-H让输出带上文件名。
如果想统计“哪些目录下包含某种错误标记的文件数量”,可以用-l参数让grep只输出文件名,然后管道给wc -l:
bash复制find . -type f -name "*.log" -exec grep -l "OutOfMemory" {} \; | wc -l
这里有个性能优化点:-exec grep对每个文件启动一次grep进程,文件一多会很慢。更高效的方式是换xargs:
bash复制find . -type f -name "*.log" -print0 | xargs -0 grep -l "OutOfMemory" | wc -l
在find结果特别庞大时,这一行比上一种快非常明显。
6. 进阶技巧:如何用这些命令完成一次完整的安全巡检
前面分别讲了命令,这里我把它们串成一个完整场景:对一台服务器做例行安全巡检,重点关注账户风险和权限风险。
第一步,列出所有能登录的用户。/sbin/nologin和/bin/false的用户没有交互登录能力,重点看那些shell是/bin/bash或/bin/sh的:
bash复制awk -F: '$7 ~ /(bash|sh)$/ {print $1}' /etc/passwd
第二步,检查这些用户里有没有密码为空的:
bash复制awk -F: '($2 == "" ) {print $1}' /etc/shadow
密码为空意味着不需要密码就能登录,这个必须第一时间修复。
第三步,找出所有设置了setuid权限的普通文件。setuid位会让普通用户以文件属主身份执行程序,是提权攻击最常用的路径:
bash复制find / -type f -perm -4000 -not -path "/proc/*" -not -path "/sys/*" 2>/dev/null
对找出来的每个结果,确认它是不是系统自带的合法程序,如果不能确认来源,就该重点关注。
第四步,找出所有“其他用户可写”的系统文件。这类文件如果存在于PATH目录或者系统服务目录下,存在被篡改的风险:
bash复制find /usr /sbin /etc -type f -perm /002 2>/dev/null
第五步,找出近期被修改的可疑文件,时间范围可以根据实际运维窗口来定:
bash复制find /etc -type f -mtime -3
一般系统配置不会天天变,如果发现/etc下有不明原因的文件被修改,就要警惕。
整趟巡检下来,用户账户管理的命令负责第一、二步,find负责第三到第五步,两类命令缺一不可。这也是为什么我建议不要把这两块知识割裂开学的根本原因。
7. 常见问题速查:我踩过的一些坑和排查建议
这一节我直接整理成问答形式,都是我实际经历过、或者帮别人排查过的高频问题。
Q1:为什么useradd创建的用户用不了sudo?
sudo权限不是用户创建时自动赋予的,需要把用户加入wheel组或者sudo组,具体看系统的sudo配置。Debian系一般是sudo组,RHEL系一般是wheel组。执行usermod -aG sudo zhangsan并重新登录后生效。
Q2:为什么usermod改完组不生效?
usermod的组变更只影响“下一次登录”。如果用户已经登录了,现有的会话里组信息不会刷新,需要退出重新登录。个别情况下,如果该用户当前有进程在运行,即使重新登录,旧进程的组关系也还是旧的,最干净的解决方法是让用户退出所有会话后再登录。
Q3:userdel删不掉用户,提示“user xxx is currently used by process”?
说明有进程还以该用户身份在跑。先确认是什么进程:ps -u username,要么停止对应服务,要么用pkill -u username杀掉进程,再执行删除。生产环境别直接pkill,先看进程是什么,确认不是重要业务再操作。
Q4:find执行时报“Permission denied”是不是出问题了?
不是,find在遍历时碰到无权限目录就会打印这条提示,属于正常情况。不想看到报错,加2>/dev/null即可,但你要知道这样也会跳过那些目录里的查找结果。
Q5:find -size +1G为什么找不到任何文件?
查一下你文件系统是否支持大文件,另外如果文件分散在不同分区,+1G只对匹配到的文件生效。更常见的原因是有些文件系统对文件大小的计算方式不同,但你用ls -lh明明看到文件有1.2G。这个我遇到过,原因出在find的-size对块设备的单位换算上,普通文件场景建议加上-type f再查一次。
Q6:xargs处理带空格文件名报错怎么办?
必须用-print0和xargs -0组合,或者根本不用管道,直接用-exec ... {} +这种批量传参的exec形式。-exec {} +会把所有匹配到的文件一次性追加到命令后面,而不是每文件一条命令,性能和空格兼容性都好一些:
bash复制find /data -type f -name "*.log" -exec chmod 644 {} +
Q7:find命令输出的文件列表排序吗?
不排序。find的遍历顺序取决于底层目录的存储顺序,通常是不确定的。如果你需要排序后再处理,管道接sort:
bash复制find /data -type f -name "*.log" | sort
Q8:如何查找最近被删除但是还被进程占用的文件?
这个场景不是find命令能直接解决的,需要配合lsof。如果一个文件被进程打开后又被删除,磁盘空间不会释放,用lsof | grep deleted可以找到这些文件,定位到对应的进程后重启或者重载服务,空间就会回收。
8. 最后再分享一个实际组合技
我最后分享一个自己日常运维中一直在用的小技巧,把账户管理和文件查找结合起来做“离职员工账号清理”的完整流程。
员工离职后,标准流程不只是删掉账号,还要确认该员工名下的文件归属。我会按这个顺序操作:
- 列出该用户所有的文件和目录:
bash复制find /home /data /opt -user zhangsan
- 把文件归属转给某个接管同事:
bash复制find /home /data /opt -user zhangsan -exec chown lisi:devops {} \;
- 确认组归属没有遗漏:
bash复制find /home /data /opt -group oldgroup
- 确认无遗漏后锁定账号备用(不直接删除,防止有重要数据来不及备份):
bash复制passwd -l zhangsan
- 观察一个月确认无异常后,再删除账号和文件。
这一套操作流程在我的实际工作中已经跑了很多遍,每次都有效。它把账户管理命令、find查找命令、权限修改命令全部串在了一条业务链里,比单一命令的堆砌实用得多。
账户和组管理这块,核心是理解/etc/passwd、/etc/group、/etc/shadow这几个文件的关联与字段含义;find这块,核心是掌握表达式求值的逻辑和常用条件组合。二三十个参数的死记硬背没有意义,真正有价值的是知道在什么场景下用什么条件、怎么组合、怎么规避坑。我把这篇文章里每个命令都在多种发行版上实测过,包括CentOS 7、Ubuntu 20.04、Rocky 9,所有命令的语法和输出兼容这些主流环境。如果你在实操中遇到这里没提到的问题,欢迎带着具体场景来交流,我有空都会回复。
