如何使用bash一次使用多个文件

时间:2010-11-29 08:35:52

标签: perl bash

我有一个perl脚本,用于处理给定目录中的某些数据文件。我在下面写了一个bash脚本来查找给定目录中的最后一个更新文件并处理该文件。

cd $data_dir
find \( -type f -mtime -1 \) -exec ./script.pl {} \;

有时,用户将多个文件复制到数据目录,因此跳过前一个文件。 perl脚本仅执行最后更新的文件。你能建议我如何使用bash脚本解决这个问题。

3 个答案:

答案 0 :(得分:3)

尝试

cd $data_dir
find \( -type f -mtime -1 \) -exec ./script.pl {} +

请注意-exec+

的终止\;

来自手册页

  

-exec command {} +
  -exec操作的此变体在所选文件上运行指定的命令,但命令行是通过在末尾附加每个选定的文件名来构建的;

现在您已将一个或多个文件名传递到perl脚本中,您可以更改perl脚本以迭代每个传入的文件名。

答案 1 :(得分:1)

如果我正确理解了这个问题,您需要处理自上次运行脚本以来在目录中创建或修改的所有文件。

在我看来,find不是确定这些文件的正确工具,因为它不知道它已经看过哪些文件。

如果在指定的时间段内运行脚本两次,则使用任何-atime / -ctime / -mtime选项将产生重复项,如果未在正确的时间执行,则会遗漏某些文件。使用这些选项的时机错综复杂并不容易处理。

我可以提出一些选择:

a)使用三个目录而不是一个:incoming / processing / done /。您的用户应该只允许将文件放入传入/。在运行perl脚本之前,将其中的任何文件移动到处理/使用简单的mv incoming/* processing/。然后你将它们从处理/移动到完成/当它结束时。

在我看来,这是最简单和最好的解决方案,也是邮件服务器等在处理此问题时使用的解决方案。如果我是你,并且没有任何特殊情况阻止你这样做,我就不再在这里阅读了。

b)让查找程序脚本touch成为一个特殊文件(例如.timestamp,可能在不同的目录中,以便用户不会篡改它)。这将允许您的脚本记住它上次运行的时间。然后使用

find \( -cnewer .timestamp -o -newer .timestamp \) -type f -exec ./script.pl '{}' ';'

为每个文件运行perl脚本。您应该修改perl脚本,以便每次都可以使用不同的文件名重复运行。如果您可以将其修改为一次接受多个文件,则还可以使用

运行它
find \( -cnewer .timestamp -o -newer .timestamp \) -type f -exec ./script.pl '{}' +

将最小化./script.pl进程的数量。当缺少.timestamp文件时,请小心处理查找脚本的第一次运行。一个好的解决方案是在这种情况下根本不使用 - *更新的选项来忽略它。另请注意,存在竞争条件,其中在查找开始之后但在触摸时间戳文件之前添加的文件将不会被处理。

c)作为(b)的变体,让脚本使用最近创建/修改的已处理文件的时间更新时间戳。这很棘手,因为find无法自行对其输出进行排序。您可以在perl脚本周围使用包装器来处理:

#!/bin/bash

for i in "$@"; do
    find "$i" \( -cnewer .timestamp -o -newer .timestamp \) -exec touch -r '{}' .timestamp ';'
done

./script.pl "$@"

如果调用它来处理具有较新mtime或ctime的文件,则会更新时间戳,从而最小化(但不会消除)竞争条件。然而它有些尴尬 - 不可避免,因为bash的[[-nt选项似乎只检查mtime。如果你的perl脚本自己处理它可能会更好。

d)让您的脚本将每个已处理的文件名及其时间戳存储在某处,然后跳过重复项。这将允许您只是将目录中的所有文件传递给它,并让它整理混乱。虽然有点棘手...

e)由于您使用的是Linux,因此您可能需要查看inotify和inotify-tools包 - 特别是inotifywait工具。通过一些脚本,它将允许您处理文件,因为它们被添加到目录中:

inotifywait -e MOVED_TO -e CLOSE_WRITE -m -r testd/ | grep --line-buffered -e MOVED_TO -e CLOSE_WRITE | while read d e f; do ./script.pl "$f"; done

这没有竞争条件,只要您的用户不创建/复制/移动任何目录而不仅仅是文件。

答案 2 :(得分:0)

perl脚本只会针对find提供的文件执行。也许您应该从-mtime -1命令中删除find选项,以便它获取目录中的所有文件?