如何避免处理先前运行期间已经处理过的文件?

如何避免处理先前运行期间已经处理过的文件?

这是一个修改定义路径中所有文件的脚本:

#!/bin/bash
FILES=/path/to/files/*
for f in $FILES
do
  [some_command_to_make_changes_into_file] $f > tmp_$f; mv tmp_$f $f
done

代码第一次运行运行良好;问题是当我第二次或第三次运行此脚本时,它再次选择所有文件。我怎么能够 不处理所有那些在上次运行中已经处理过的文件?我无法更改文件名或路径。

答案1

您可以使用“已处理”标记文件。

#!/bin/bash
TAG="done"
FILES=/path/to/files/*
for f in $FILES
do
  case "$f" in
    *.$TAG) # process mark-files
      echo "# TAG-FILE=$f"
      b=`echo $f | sed "s/\.$TAG\$//"` # get base file of the mark-file
      echo "#   FILE=$b"
      if [ ! -f "$b" ] ; then
        echo "#  TAG-FILE REMOVE" 
        rm $f # remove mark-file without base file
      file
      continue # do not process mark-files themselves
      ;; 
  esac
  if [ -f "$f.TAG" ] ; then
    echo "# FILE=$f"
    echo "#   TAG-FILE PRESENT"
    continue # mark-file present - skip processing
  fi
  echo "# FILE=$f"
  echo "#   TAG-FILE ABSENT => PROCESSING"


  # [some_command_to_make_changes_into_file] $f > tmp_$f; mv tmp_$f $f

  echo "#   PROCESSED"
  touch "$f.$TAG" # create mark-file
  if [ -f "$f.TAG" ] ; then
    echo "#   TAG-FILE CREATED"
  else
    echo "#   TAG-FILE CREATION FAILED!"
    exit
  fi
done

可能的改进:您可以将标记文件存储在另一个目录中。

答案2

如果您使用的是现代文件系统,例如ext4、等btrfsxfs您可以利用扩展文件属性- 在这种情况下,您可以使用“用户”名称空间属性。因此,检查每个文件的特定属性 - 如果设置为1,则跳过该文件,否则处理该文件然后设置属性。假设该属性及其值定义为

user.validation="processed"

那么你的代码可以做这样的事情:

for f in /path/to/files/*
  do
    if ! getfattr -n user.validation "$f" >/dev/null 2>&1
      then
        echo "$f"
        setfattr -n user.validation -v processed "$f"
    fi
  done

替换echo为您的命令...另外,请注意循环 glob 扩展结果的正确方法 - 使用 glob 或for将结果保存在数组中并迭代其元素:

filez=( /path/to/files/* )
for f in "${filez[@]}"

1:为了简单起见,脚本仅检查属性是否已设置 - 它不检查其值。

答案3

这可能是使用一些的好例子构建自动化类似工具GNUmake或者忍者, ETC...

例如,给定一些foo.txt输入文件,您可以决定将其转换放入foo.outtouch 一些foo.done 空标记文件中(请参阅安菲的回答),并在你的Makefile 为了这一切。顺便说一句,这些标记(或日志)文件可以位于其他目录中。

GNU make (以及ninja等等...)不仅可以用来编译东西,而且更一般地可以用来根据文件时间戳触发处理(如果您采用一些约定)。

并且make -j 4 您最多可以并行执行四个任务来进行该处理,因此您可能会等待更少。

答案4

您可以使用 make 在另一个目录中创建“已处理”标记文件。

# version for gnu-make

# Path to directory with jobs files
DIR_JOBS=/path/to/files
# Path to directory with mark files marking processes job files
DIR_MARKS=/path/to/mark-files

JOBS=$(wildcard $(DIR_JOBS)/*)
MARKS=$(wildcard $(DIR_MARKS)/*)
JOBS_MARKS=$(patsubst $(DIR_JOBS)/%,$(DIR_MARKS)/%.done, $(JOBS))

$(DIR_MARKS)/%.done: $(DIR_JOBS)/%
        @echo '###' make $@ from $<
        # your command to process the job file - should return 0 on success
        touch $@

ALL: $(JOBS_MARKS)
        @echo '###' for debug purposes
        @echo JOBS=$(JOBS)
        @echo JOBS_MARKS=$(JOBS_MARKS)
        @echo MARKS=$(MARKS

相关内容