我创建了一个小示例脚本,它是我真实脚本的简化版本,基本上如下所示:
#!/bin/bash
echo "start" > /home/myName/log.txt
#get list with all attached devices
for i in $(lsblk -lo name,fstype,hotplug,type|grep '1 part$'|tr -s ' ' ' '|sed 's/ 1 part$//'|grep ' ..*$'|tr ' ' '_')
do
echo $i >> /home/myName/log.txt
done
如果我直接在终端中调用脚本,一切都会正常工作。因此日志文件中的返回内容就是这样的。
start
sdc1_vfat
但是一旦从 udev 规则调用该脚本,循环就不再起作用。日志文件中的输出只有
start
循环不再起作用。
/dev/udev/ 中的规则如下
SUBSYSTEM=="usb", ACTION=="add", RUN+="/bin/bash /usr/bin/myScript.sh"
谁知道这是什么原因造成的?
这里有一些更多信息,并根据您的回答建议了一个重新修改的版本。
这是 udev 规则:
# check usb sdb1 plugged unplugged
SUBSYSTEM=="block", ACTION=="add", RUN+="/bin/bash /usr/bin/usb_mount.sh"
SUBSYSTEM=="block", ACTION=="remove", RUN+="/bin/bash /usr/bin/usb_unmount.sh"
安装脚本现在如下所示:
#!/bin/bash
#general definitions
MNT_PATH="/media/USB_DRIVE"
DEV_ID="sdc1"
# check connected device
udevadm info -q all "/dev/$DEV_ID" | tr '\n' ' ' | grep "/dev/$DEV_ID" | grep "ID_FS_VERSION=FAT32"
# check return
if [ $? -eq 0 ]
then
# create folder and mount
mkdir -p $MNT_PATH
mount -o rw,user,exec,umask=0000 "/dev/$DEV_ID" $MNT_PATH
exit
fi
如果我检查安装命令,则表明exit code is 0
它已成功处理。文件夹已正确创建,但驱动器未安装。如果直接在终端中调用脚本,则一切都按预期工作。但如果由调用,则udev
它未安装。
我仍然不知道现在的问题:
- 这是一个时间问题吗——即使
udevadm info -q all /dev/sdb*
返回了连接的设备? - 是权限问题还是路径问题?
有什么想法我可以找到原因吗?
附加信息
刚刚发现,报告了syslog
an中的内容exit code 127
。所以这似乎是权限问题。但我如何确保udev
脚本以 root 身份运行?
答案1
Bash 的行为是一样的...它只是lsblk
返回一个空字符串...原因是,在处理完插入同一磁盘所触发的所有规则之前,它udev
不会使您的磁盘可用。/dev
因此,监控和安装该磁盘分区的方法根本行不通。
或者,您可以通过以下两种方式之一实现您的目标。
监视任何磁盘上的特定分区名称
这是一个更便携的(独立于udisks
和udev
规则)bash脚本运行时将监视您指定的某个USB(或其他)磁盘分区(例如/dev/sdb1
假设/dev/sdb
始终是空闲的并且为第一个插入的 USB 磁盘保留),当插入 USB 磁盘时将其挂载到您指定的挂载点,当拔出 USB 磁盘时将其卸载,并将所有事件记录到您指定的日志文件中...阅读脚本中的注释以获取帮助。
该脚本需要以管理员权限运行...因此:
- 用 运行它
sudo /bin/bash scriptfile
。 - 添加一个 cron-job(启动过程完成后只需运行一次) 将其添加到 root 的 crontab 中
sudo crontab -e
。 - 添加systemd服务(并启用服务)来运行它。
#!/bin/bash
# Set the name of the partition to be monitored.
mpartition="/dev/sdb1"
# Set the full path to the mount-point.
mount_point="/home/user/USB_DRIVE"
# Set the full path to the logfile(will be created if it doesn't exist)
log_file="/home/user/usb_mount.log"
# Start "inotifywait"(need be installed first with "sudo apt install inotify-tools") to monitor the partition
inotifywait -q -m --include "$mpartition" -e create -e delete /dev/ |
while read -r directory event partition; do
if [ "$event" == "CREATE" ]; then
note=$(/usr/bin/mount -v -o rw "$directory$partition" "$mount_point" 2>&1) # If needed, add extra options after -o like "-o rw,umask=000" to allow all write and read
status="$?"
if [ "$status" -eq 0 ]; then
echo "$(date): Successful mount with exit code $status [$note]" >> "$log_file"
else
echo "$(date): Failed mount with exit code $status [$note]" >> "$log_file"
fi
elif [ "$event" == "DELETE" ]; then
note=$(/usr/bin/umount -v "$mount_point" 2>&1)
status="$?"
if [ "$status" -eq 0 ]; then
echo "$(date): Successful un-mount with exit code $status [$note]" >> "$log_file"
else
echo "$(date): Failed un-mount with exit code $status [$note]" >> "$log_file"
fi
fi
done
监视特定磁盘上的特定分区
有很多方法可以识别某个磁盘上的某个分区...最合适的方法是连接您要使用的 USB 磁盘,然后查看下面的内容/dev/disk/
以找到在系统上识别磁盘的其他方法...这样做ls /dev/disk/
您将获得:
$ ls /dev/disk/
by-id by-label by-partlabel by-partuuid by-path by-uuid
上面每一个都是包含指向您的磁盘的符号链接的目录,名称说明了一切,剩下的就是由您选择如何识别您的磁盘...一个更可靠的方法是,by-id
因为这应该是一个唯一的固定字符串,包含磁盘设备本身的制造商名称和序列号,后面是磁盘分区的分区号...一个有用的是 USB 磁盘也以usb-
...为前缀,所以ls /dev/disk/by-id/
会产生如下结果:
usb-SanDisk_Cruzer_Blade_4C530200811130110350-0:0
usb-SanDisk_Cruzer_Blade_4C530200811130110350-0:0-part1
一旦您识别出您的设备的 ID,您就可以简单地检查它是否已连接,例如:
$ [ "$(readlink -e /dev/disk/by-id/usb-SanDisk_Cruzer_Blade_4C530200811130110350-0:0)" ] && echo "connected"
connected
/dev
并像这样知道它的名字readlink
:
$ readlink -f /dev/disk/by-id/usb-SanDisk_Cruzer_Blade_4C530200811130110350-0:0
/dev/sdb
所以,脚本就变成这样:
#!/bin/bash
# Set the ID of the partition to be monitored.
mpartition="usb-SanDisk_Cruzer_Blade_4C530200811130110350-0:0-part1"
# Set the full path to the mount-point.
mount_point="/home/user/USB_DRIVE"
# Set the full path to the logfile(will be created if it doesn't exist)
log_file="/home/user/usb_mount.log"
# Start "inotifywait"(need be installed first with "sudo apt install inotify-tools") to monitor the partition
inotifywait -q -m --include "$mpartition" -e create -e delete /dev/disk/by-id/ |
while read -r directory event partition; do
if [ "$event" == "CREATE" ]; then
device=$(/usr/bin/readlink -f /dev/disk/by-id/"$mpartition")
note=$(/usr/bin/mount -v -o rw "$device" "$mount_point" 2>&1) # If needed, add extra options after -o like "-o rw,umask=000" to allow all write and read
status="$?"
if [ "$status" -eq 0 ]; then
echo "$(date): Successful mount with exit code $status [$note]" >> "$log_file"
else
echo "$(date): Failed mount with exit code $status [$note]" >> "$log_file"
fi
elif [ "$event" == "DELETE" ]; then
note=$(/usr/bin/umount -v "$mount_point" 2>&1)
status="$?"
if [ "$status" -eq 0 ]; then
echo "$(date): Successful un-mount with exit code $status [$note]" >> "$log_file"
else
echo "$(date): Failed un-mount with exit code $status [$note]" >> "$log_file"
fi
fi
done