udev匹配u盘应监听subsystem=="block"且devtype=="disk",而非usb子系统;需校验attrs{removable}=="1"及厂商/产品id,并用udevadm test模拟验证规则。

Udev规则怎么匹配U盘设备
Udev靠SUBSYSTEM、ATTRS、ENV等键值匹配设备事件,U盘插拔本质是block子系统中sdX设备的add/remove事件。别用usb子系统匹配——它触发太早(还没完成存储设备初始化),脚本里/dev/sdX可能还不存在。
正确做法是监听SUBSYSTEM=="block"且DEVTYPE=="disk",再加一层校验避免误触:比如排除内置硬盘(ATTRS{removable}=="1")、过滤USB厂商(ATTRS{idVendor}=="0781")或型号(ATTRS{idProduct}=="5567")。
验证设备属性可用:
udevadm info --name=/dev/sdb --attribute-walk | grep -E "(idVendor|idProduct|removable|DEVTYPE)"
为什么脚本不执行或执行失败
Udev规则里RUN+=调用的脚本受严格限制:没有$PATH、无终端、用户是root但环境极简。常见失败点:
- 脚本没加
#!/bin/bash或没chmod +x - 用了
systemctl、notify-send等依赖用户会话的命令 - 路径写相对路径(如
./backup.sh),必须用绝对路径(/usr/local/bin/usb-handler.sh) - 脚本里访问
/dev/sdb1太早——Udev规则触发时分区表可能还没被内核识别,加sleep 1或改用udevadm settle不靠谱,应改用inotifywait监听/sys/block/sdb/sdb1目录出现
如何安全挂载并执行后续操作
Udev本身不处理挂载,它只负责“通知”。想自动挂载+运行脚本,分两步走:
第一步:Udev规则只做最小动作,例如写标记文件或触发systemd服务:
RUN+="/bin/sh -c 'echo $(date) > /run/usb-arrived'"
第二步:用systemd服务监听该标记(或直接用PathExistsGlob=/sys/block/sd*),服务里做挂载和业务逻辑。这样能用完整环境、支持日志、可设依赖(如After=local-fs.target)。
硬要在Udev里挂载?确保:
• 加ENV{ID_FS_TYPE}!="", ENV{ID_FS_TYPE}!="ntfs"过滤无文件系统的盘
• 用mount -o uid=1000,gid=1000 /dev/sdb1 /mnt/usb指定用户权限,否则普通用户无法访问
• 挂载前检查/mnt/usb是否已挂载(grep -q "/mnt/usb " /proc/mounts)
调试Udev规则的实际方法
别靠重启测试。先用udevadm monitor --subsystem-match=block看插拔时是否输出add@/devices/.../sdb事件;再用udevadm test $(udevadm info -q path -n /dev/sdb)模拟触发,它会打印所有匹配规则和RUN命令是否被解析。
关键点:
• 规则文件必须放在/etc/udev/rules.d/且以.rules结尾(如99-usb-auto.rules)
• 修改后运行sudo udevadm control --reload-rules,不是restart udev
• RUN命令的输出不会显示在终端,重定向到文件才能看到错误:
RUN+="/usr/local/bin/usb-handler.sh > /tmp/usb.log 2>&1"
真正麻烦的是异步性:Udev进程在设备事件上下文中运行,超时默认为30秒,脚本卡住会导致后续设备事件阻塞。任何长操作(如复制大文件)必须后台化:/usr/local/bin/usb-handler.sh &。











