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

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

我希望我的 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"

然后/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

现在,当我插入 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

但同样的情况再次发生:系统在复制过程中停止。

那么我的系统出了什么问题呢?

我该怎么做才能告诉系统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

但这也没有帮助!同样的场景再次发生!这次更糟糕:它根本没有复制任何文件!

更新3

我将其更改/etc/udev/rules.d/10-usbstick.rules为以下内容:

ACTION=="add", SUBSYSTEM=="block", KERNEL=="sd[a-z]1" SYMLINK+="usbflash", RUN+="/path/to/myscript.sh"

现在效果很好。它复制所有文件。但有一个新问题:它无法关闭!

更新4

我发现了一些新东西:

当我myscript.sh直接从终端运行时,它工作得很好:删除旧文件,复制新文件,然后关闭系统。完美的。

myscript.sh那么,为什么当我从 udev 规则调用它时它不能完美执行呢?

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

答案1

wait除非它在后台运行(而您的不是),否则 for 命令是没有意义的。您可能缺少的是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

我必须承认我有点困惑,因为您的描述似乎表明您想要更新 USB 记忆棒上的文件。但是你的代码更新了文件/path/to/my/folder USB 记忆棒而不是写入/mnt/usb/...

答案2

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

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

原创nohup建议

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

udev规则:

ACTION=="add", SUBSYSTEM=="block", KERNEL=="sd[a-z]1" SYMLINK+="usbflash", RUN+="/path/to/mywrapper.sh"

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

#!/bin/sh
nohup /path/to/myscript.sh >/log/myscript.log 2>&1 &

然后myscript.sh就可以了。

较新的systemd建议

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

ACTION=="add", SUBSYSTEM=="block", KERNEL=="sd[a-z]1" SYMLINK+="usbflash", RUN+="/usr/bin/systemctl start my-usb-backup.service"

通过简单的一次性服务my-usb-backup.service

[Unit]
Description=run myscript
[Service]
Type=oneshot
ExecStart=/path/to/myscript.sh

也可以看看:

相关内容