递归移动文件,但前提是它们未被其他进程打开

递归移动文件,但前提是它们未被其他进程打开

我想修改下面的脚本文本,以更改文件权限、所有者并移动它,前提是该文件未被其他进程打开。

cd /mnt/usbdrive/DVR
sudo chown 777 -R /mnt/usbdrive
sudo chmod 777 -R /mnt/usbdrive
find .  -mindepth 2 -type f -name '*.ts' -exec mv -t /mnt/usbdrive {} +

答案1

对于您的情况,一个简单而精简的find 命令可能是:

find .  -mindepth 2 -type f -name '*.ts' -exec fuser -s {} \; -a -exec mv /mnt/usbdrive {} \;

这里我们利用了find的表达能力:注意-a运算符(意​​思是“和”),这样mv只有当fuser以 0 退出时才会执行,这意味着文件已打开。

这是最安全的命令,能够处理文件名中可能存在的任何字符。

但如果该目录中有很多文件,此命令也可能会非常慢。事实上,您已经使用了{} +沿着选项mv-t语法来减轻这种负担。

不幸的是,我们不能只对这两个-exec操作使用该语法,因为fuser 当任何人所指示的文件已打开,我们甚至不知道哪些文件是由find.

我们仍然可以在这里使用{} + 语法,但我们需要一个更复杂的命令。像这样的一个:

find . -mindepth 2 -type f -name '*.ts' -exec fuser {} + 2>&1 | sed 's/^\(.\+\):.*/\1/' | xargs mv -t /mnt/usbdrive

分解所使用的内容-execfind我们基本上fuser在一次运行中考虑了所有文件,但也通过 sed 过滤其输出以仅获取文件名(fuser输出 PID 和文件名),最终将它们一次性通过管道传输到xargs 正在运行的原始命令mv。为了进行测试,我建议添加该-p选项,xargs以查看确认后会移动哪些内容。

然后,我还注意到您说您想更改权限和所有者除了仅当文件未打开时才移动文件,但我看到您事先对整个目录做了chown加号。 chmod(顺便说一句,chown 777根本没有意义,你想在那里放一个用户名..除非777确实是你系统中的用户ID,但我对此表示怀疑)。

因此,如果您希望按照您所说的进行操作,您可以xargs通过将这些命令打包到 shell 的复合命令中来将它们添加到 中。

像这样:

find . -mindepth 2 -type f -name '*.ts' -exec fuser {} + 2>&1 | sed -e 's/^\(.\+\):.*/\1/' | xargs sh -c 'echo sudo chmod 777 "${@}"; echo sudo chown user "${@}"; echo mv -t /mnt/usbdrive "${@}"' --

这其实只是节目将运行的命令。我建议您尝试一下,当您准备好真正应用它时,只需删除 s 即可echo

重要的提示:后两个允许使用find's{} +语法的命令无法处理嵌入换行符的文件名,因为sed.处理这些问题是可能的,但由于fuser的特定输出,会变得更加复杂。我认为假设您的文件名没有嵌入换行符是合理的,否则您可能宁愿使用第一个更简单但更慢的命令。

相关内容