Como evitar o processamento de arquivos que já foram processados durante execuções anteriores?

2

Aqui está um script que modifica todos os arquivos em um caminho definido:

#!/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

O código está funcionando bem para a primeira execução; O problema é quando eu executo esse script uma segunda ou terceira vez, ele pega novamente todos os arquivos. Como posso não processar todos os arquivos que já foram processados na execução anterior? Não consigo alterar nomes de arquivo ou caminho.

    
por serenesat 18.10.2017 / 09:48

4 respostas

2

Você pode usar o (s) arquivo (s) de marcação "processado (s)".

#!/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

Melhoria possível: Você pode armazenar arquivos de marcação em outro diretório.

    
por 18.10.2017 / 10:16
0

Esse pode ser um bom caso para usar alguma ferramenta de automação de construção como GNU make ou ninja , etc ...

Por exemplo, dado algum arquivo de entrada foo.txt , você pode decidir colocar sua transformação em foo.out ou touch some foo.done arquivo de marca vazio (consulte resposta do Anfi ) e tenha regras em seu Makefile por tudo isso. BTW, esses arquivos mark (ou log) poderiam estar em algum outro diretório.

O GNU make (e ninja , etc ...) pode ser usado não apenas para compilar coisas, mas mais geralmente para acionar o processamento baseado em registros de data e hora de arquivos (se você adotar algumas convenções).

E com make -j 4 você teria até quatro tarefas em paralelo para fazer esse processamento, então provavelmente esperaria menos.

    
por 18.10.2017 / 10:17
0

Você pode usar o make para criar arquivos de marca "processados" em outro diretório.

# 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
    
por 18.10.2017 / 12:57
0

Se você estiver usando um sistema de arquivos moderno como ext4 , btrfs , xfs etc, aproveite os atributos de arquivo estendidos - nesse caso, você poderia usar um atributo de namespace "user". Portanto, verifique cada arquivo para esse atributo específico - se ele for 1 , pule o arquivo, caso contrário, processe o arquivo e, em seguida, defina o atributo. Digamos que o atributo e seu valor tenham sido definidos como

user.validation="processed"

então seu código poderia fazer algo assim:

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

Substitua echo pelos seus comandos ... Além disso, observe a maneira correta de executar o loop sobre o resultado da expansão glob - use o glob com for ou salve o resultado em uma matriz e repita seus elementos:

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

1: para simplificar, o script verifica apenas se o atributo está definido - ele não verifica seu valor.

    
por 18.10.2017 / 15:45