Omi*_*989 5 process cp shell-script raspberry-pi
我希望我的 RPi 2(使用MiniBian
(基于 Debian 的Raspbian
操作系统的最小版本)作为其操作系统)在检测到插入了 USB 闪存时执行脚本。所以这就是我所做的:
我/etc/udev/rules.d/10-usbstick.rules
用这些内容创建:
ACTION=="add", SUBSYSTEM=="block", KERNEL=="sd*" SYMLINK+="usbflash", RUN+="/path/to/myscript.sh"
Run Code Online (Sandbox Code Playgroud)
然后/path/to/myscript.sh
用这些内容创建:
#!/bin/bash
mount /dev/usbflash /mnt/
service omxd stop
rm -r /path/to/myfolder/*
cp -f /mnt/*.mp4 /path/to/myfolder/
cp -f /mnt/*.avi /path/to/myfolder/
sleep 1
umount /dev/usbflash
halt
Run Code Online (Sandbox Code Playgroud)
现在,当我插入 USB 闪存时,它会识别它,安装它,停止omxd
守护进程并删除所有旧文件。
但问题是它halt
在复制所有文件之前关闭 ( )。后来查了一下,发现只有1个文件被复制了,而且没有被正确复制,就像halt
在复制过程中执行了命令一样。
所以,我决定使用wait
command 来确保halt
命令只在最后执行。我编辑的/path/to/myscript.sh
文件是这样的:
#!/bin/bash
mount /dev/usbflash /mnt/
PID1 = $!
wait PID1
service omxd stop
rm -r /path/to/myfolder/*
PID2 = $!
wait PID2
cp -f /mnt/*.mp4 /path/to/myfolder/
PID3 = $!
wait PID3
cp -f /mnt/*.avi /path/to/myfolder/
PID4 = $!
wait PID4
sleep 1
umount /dev/usbflash
PID5 = $!
wait PID5
halt
Run Code Online (Sandbox Code Playgroud)
但同样的情况再次发生:系统在复制过程中间停止。
那么我的系统有什么问题?
halt
只有在所有新文件都成功复制后,我该怎么做才能告诉系统!?
更新 1
添加sync
之前umount
和halt
没有工作。同样的场景再次发生。
更新 2
我编辑的/path/to/myscript.sh
文件如下:
mkdir -p /mnt/usb
if mount /dev/usbflash /mnt/usb
then
service omxd stop
rm -r /path/to/myfolder/*
cp -f /mnt/usb/*.mp4 /path/to/myfolder/
cp -f /mnt/usb/*.avi /path/to/myfolder/
sync
umount /mnt/usb
sync
shutdown -h now
fi
Run Code Online (Sandbox Code Playgroud)
但它也没有帮助!同样的场景再次发生!这一次更糟:它根本没有复制任何文件!
更新 3
我将其更改/etc/udev/rules.d/10-usbstick.rules
为以下内容:
ACTION=="add", SUBSYSTEM=="block", KERNEL=="sd[a-z]1" SYMLINK+="usbflash", RUN+="/path/to/myscript.sh"
Run Code Online (Sandbox Code Playgroud)
现在效果很好。它复制所有文件。但是有一个新问题:它不会关闭!
更新 4
我发现了一些新东西:
当我myscript.sh
直接从终端运行时,它工作得很好:删除旧文件,复制新文件,然后关闭系统。完美的。
那么,myscript.sh
当我从 udev 规则调用它时,为什么它不能完美执行?
复制文件后有没有其他方法可以关闭系统!?
wait
除非它在后台运行(你的不是),否则命令没有意义。您可能缺少的是sync
强制所有写入媒体的内容,尽管这应该作为umount
命令的一部分发生。
我很想看看这个简化的脚本是否能如你所愿:
#!/bin/bash
#
export PATH=/usr/local/bin:/bin:/usr/bin:/sbin:/usr/sbin
mkdir -p /mnt/usb
if mount /dev/usbflash /mnt/usb
then
service omxd stop
rm -r /path/to/myfolder/*
cp -f /mnt/usb/*.mp4 /path/to/myfolder/
cp -f /mnt/usb/*.avi /path/to/myfolder/
sync
umount /mnt/usb
sync
shutdown -h now
fi
Run Code Online (Sandbox Code Playgroud)
我必须承认我有点困惑,因为您的描述似乎表明您想要更新 U 盘上的文件。但是您的代码/path/to/my/folder
从U 盘更新文件而不是写入/mnt/usb/...
我不知道为什么更改内核名称会产生影响(也许在允许更多时间完成工作sd*1
后运行?),但 udev 不喜欢事件中长时间运行的操作:sd*
\n\n\nudev 不适合启动守护进程或其他长时间运行的进程;事件处理完成后,分叉的进程(无论是否分离)都将被无条件终止。
\n
nohup
建议我最初建议nohup
在完全阅读我自己的链接之前:)——这表明这实际上可能行不通
udev规则:
\n\nACTION=="add", SUBSYSTEM=="block", KERNEL=="sd[a-z]1" SYMLINK+="usbflash", RUN+="/path/to/mywrapper.sh"\n
Run Code Online (Sandbox Code Playgroud)\n\nmywrapper.sh
(注意:如果您不重定向输出,nohup 可能会在您的目录中散布文件nohup.out
):
#!/bin/sh\nnohup /path/to/myscript.sh >/log/myscript.log 2>&1 &\n
Run Code Online (Sandbox Code Playgroud)\n\n然后就myscript.sh
可以了。
systemd
建议下面的第三个链接建议在设备插入时关闭 systemd 服务。由于确保设备信息传递到服务,该博客条目所做的工作比我认为您需要的更多,我认为您可以简单地使用systemd 作为守护进程的方法:
\n\nACTION=="add", SUBSYSTEM=="block", KERNEL=="sd[a-z]1" SYMLINK+="usbflash", RUN+="/usr/bin/systemctl start my-usb-backup.service"\n
Run Code Online (Sandbox Code Playgroud)\n\n通过简单的一次性服务my-usb-backup.service
:
[Unit]\nDescription=run myscript\n[Service]\nType=oneshot\nExecStart=/path/to/myscript.sh\n
Run Code Online (Sandbox Code Playgroud)\n\n也可以看看:
\n\n