如何等待复制过程(cp)完成?

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在复制过程中执行了命令一样。

所以,我决定使用waitcommand 来确保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之前umounthalt没有工作。同样的场景再次发生。

更新 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 规则调用它时,为什么它不能完美执行?

复制文件后有没有其他方法可以关闭系统!?

roa*_*ima 6

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/...


Dea*_*evy 2

我不知道为什么更改内核名称会产生影响(也许在允许更多时间完成工作sd*1后运行?),但 udev 不喜欢事件中长时间运行的操作:sd*

\n\n
\n

udev 不适合启动守护进程或其他长时间运行的进程;事件处理完成后,分叉的进程(无论是否分离)都将被无条件终止。

\n
\n\n

原创nohup建议

\n\n

我最初建议nohup在完全阅读我自己的链接之前:)——这表明这实际上可能行不通

\n\n

udev规则:

\n\n
ACTION=="add", SUBSYSTEM=="block", KERNEL=="sd[a-z]1" SYMLINK+="usbflash", RUN+="/path/to/mywrapper.sh"\n
Run Code Online (Sandbox Code Playgroud)\n\n

mywrapper.sh(注意:如果您不重定向输出,nohup 可能会在您的目录中散布文件nohup.out):

\n\n
#!/bin/sh\nnohup /path/to/myscript.sh >/log/myscript.log 2>&1 &\n
Run Code Online (Sandbox Code Playgroud)\n\n

然后就myscript.sh可以了。

\n\n

较新的systemd建议

\n\n

下面的第三个链接建议在设备插入时关闭 systemd 服务。由于确保设备信息传递到服务,该博客条目所做的工作比我认为您需要的更多,我认为您可以简单地使用systemd 作为守护进程的方法:

\n\n
ACTION=="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

\n\n
[Unit]\nDescription=run myscript\n[Service]\nType=oneshot\nExecStart=/path/to/myscript.sh\n
Run Code Online (Sandbox Code Playgroud)\n\n

也可以看看:

\n\n\n