processa arquivos em um diretório como eles aparecem [duplicados]

4

Eu estou tentando escrever um processo etl simples que procuraria por arquivos em um diretório a cada minuto e, em caso afirmativo, carregá-los em um sistema remoto (através de um script) e, em seguida, excluí-los.

Coisas que complicam isso: o carregamento pode demorar mais de um minuto. Para contornar isso, imaginei que poderia mover todos os arquivos para um diretório de processamento temporário, agir sobre eles e depois excluí-los de lá. Além disso, na minha tentativa de melhorar o script de linha de comando, estou tentando uma solução mais elegante. Comecei escrevendo um script simples para realizar minha tarefa, mostrado abaixo:

#!/bin/bash

for i in ${find /home/me/input_files/ -name "*.xml"}; do
FILE=$i;
done;
BASENAME='basename $FILE'
mv $FILE /tmp/processing/$BASENAME
myscript.sh /tmp/processing/$BASENAME other_inputs
rm /tmp/processing/$BASENAME

Esse script remove o arquivo do diretório de processamento quase imediatamente (o que interrompe o problema de processamento duplicado), limpa depois de si mesmo no final e permite que o arquivo seja processado no meio.

No entanto, este é o U / Linux, afinal. Eu sinto que eu deveria ser capaz de realizar tudo isso em uma única linha, canalizando e movendo as coisas em vez de um script volumoso para manter.

Além disso, usando paralelamente ao processo concorrente, isso seria uma vantagem.

Adendo : algum tipo de fila FIFO pode ser a resposta para isso também. Ou talvez algum outro tipo de observador de diretórios em vez de um cron. Estou aberto para todas as sugestões que são mais elegantes do que o meu pequeno roteiro. O único problema é que os arquivos no "diretório de entrada" são tocados momentos antes de serem gravados, então algum tipo de coisa! -size -0 seria necessário para lidar apenas com arquivos reais.

    
por J Jones 29.02.2012 / 05:20

3 respostas

4

Parece que você deve simplesmente escrever um pequeno script de processamento e usar o GNU Parallel para processamento paralelo:

link

Então, algo assim:

inotifywait -q -m -r -e CLOSE_WRITE --format %w%f my_dir |
  parallel 'mv {} /tmp/processing/{/};myscript.sh /tmp/processing/{/} other_inputs; rm /tmp/processing/{/}'

Assista aos vídeos de introdução para saber mais: link

Editar:

É necessário que o myscript.sh possa lidar com arquivos de tamanho 0 (por exemplo, ignorá-los).

Se você pode evitar o touch que você pode fazer:

inotifywait -q -m -r -e CLOSE_WRITE --format %w%f my_dir |
  parallel myscript.sh {} other_inputs

Instalar o GNU Parallel é tão fácil quanto:

wget http://git.savannah.gnu.org/cgit/parallel.git/plain/src/parallel
chmod 755 parallel
    
por 29.02.2012 / 14:36
3

Primeiro, seu script funcionará em um arquivo (o último da lista). Além disso, não acho que um forro seja sempre apropriado ou elegante. Cron faz muito nos bastidores, e você precisa ser capaz de rever as coisas que falham. A execução do cron "freqüentemente" pode ser um problema. Você pode acabar com dezenas desses processos em execução, tornando os sistemas mais lentos, já que todos eles estão tentando processar os arquivos em suas filas.

Isso é o que eu faria.

Dir="$HOME/input_files"   # never hardcode when you have variables
for filename in "$Dir"/*.xml; do
    # is the file non-empty AND is it still there, or may caught by another
    # process
    if [ -s "$filename" ]; then
        # move files locally will be faster than crossing filesystems to /tmp
        mkdir -p "$Dir/.processing"
        # temp name should use pid, just in case another input with the same name comes in
        tempname="$Dir/.processing/'basename $filename .xml'.$$"
        mv "$filename" "$tempname"
        # send stdout and stderr to a .output file
        myscript.sh "$tempname" other_inputs > "$tempname.output" 2>&1
        rc=$?
        if [ $rc -eq 0 ]; then
            rm "$tempname" "$tempname.output"
        else
            echo "Error processing $filename; rc=$rc" >&2
            echo "File in $tempname" >&2
        fi
    done

Isso removerá o arquivo após o processamento ou, por erro, manterá o arquivo no diretório .processing , incluindo a saída do comando. O comando acima não controla nada, mas permite que mais de um seja executado sem interferir um no outro. Há outras questões sobre como criar filas de trabalho bastante eficientes para aumentar.

    
por 29.02.2012 / 06:08
1

Use a interface inotify (7) para monitorar o diretório de entrada em vez de pesquisar através do cron. O inotify-tools fornece o programa inotifywait que você pode usar para monitorar o diretório se não quiser escrever código na interface de chamada do sistema.

    
por 29.02.2012 / 06:36