Script para monitorar a pasta de novos arquivos?

97

Como detectar novos arquivos em uma pasta com um script ? Eu gostaria de processar os arquivos assim que eles são criados na pasta. Isso é possível ou tenho que agendar um script com que verifica novos arquivos a cada minuto ou mais?

    
por ihatetoregister 19.11.2011 / 17:08

9 respostas

124

Você deve considerar o uso de inotifywait , como exemplo:

inotifywait -m /path -e create -e moved_to |
    while read path action file; do
        echo "The file '$file' appeared in directory '$path' via '$action'"
        # do something with the file
    done

No Ubuntu inotifywait é fornecido pelo pacote inotify-tools . A partir da versão 3.13 (atual no Ubuntu 12.04) inotifywait incluirá o nome do arquivo sem a opção -f. Versões mais antigas podem precisar ser coagidas. O que é importante notar é que a opção -e para inotifywait é a melhor maneira de fazer a filtragem de eventos. Além disso, o comando read pode atribuir a saída posicional a várias variáveis que você pode optar por usar ou ignorar. Não há necessidade de usar o grep / sed / awk para pré-processar a saída.

    
por 19.11.2011 / 17:35
23

Prefiro incron , pois é mais fácil gerenciá-lo. Essencialmente, é um serviço que aproveita inotify e você pode configurar configurações para executar ações com base nas operações de alteração de arquivos.

Ex:

<directory> <file change mask> <command or action>  options
/var/www/html IN_CREATE /root/scripts/backup.sh

Você pode ver um exemplo completo aqui: link

    
por 03.05.2013 / 22:15
14

Eu apenas criei isso, e não vejo grandes problemas com ele, além de uma pequena chance de perder arquivos entre as verificações.

while true
do
       touch  ./lastwatch
       sleep 10
       find /YOUR/WATCH/PATH -cnewer ./lastwatch -exec SOMECOMMAND {} \;
done

Se o processamento do seu arquivo não demorar muito, você não deve perder nenhum arquivo novo. Você também pode conhecer as atividades ... Não é à prova de bala, mas serve a alguns propósitos sem ferramentas externas como inotify.

    
por 14.12.2015 / 11:08
9

Eu estou supondo que a pasta de destino (eu vou chamá-lo isempty apenas por conveniência) está vazia e você está esperando por um ou mais arquivos para serem soltos lá.

Você pode usar o seguinte comando:

ls -1A isempty | wc -l

apenas para verificar se a pasta ainda está vazia, na verdade ela retornará um 0 se não houver novo arquivo (por isso a pasta isempty ainda está vazia) ou, por outro lado, retornará um valor maior de 0 (na verdade, o número de arquivos atualmente na pasta).

Dito isso, um teste bobo se / então pode fazer o resto do trabalho:

if [ $(ls -1A isempty | wc -l) -gt 0 ] ; then do_something ; fi

É claro que a função do_something terá que manipular o (s) arquivo (s) dentro da pasta isempty e depois removê-lo (s) da própria pasta após o processamento.

Adicionar uma linha como a seguinte no seu crontab executará a verificação uma vez por minuto e acionará a ação do_something se a pasta não estiver vazia, é claro:

* * * * *     if [ $(ls -1A isempty | wc -l) -gt 0 ] ; then do_something ; fi
    
por 19.11.2011 / 21:30
5

Se você quiser detectar novos arquivos, processe-os e, no final, exclua os arquivos que você pode usar. systemd.path . Este método baseia-se em inotify. Existe uma opção DirectoryNotEmpty, portanto, o systemd pode executar seu script sempre que detectar quaisquer arquivos no diretório. Você tem que lembrar que só funcionará se você puder deletar os arquivos procedidos e o script deixar o diretório vazio.

Primeiro prepare o arquivo mymonitor.service

[Unit]
Description=Start the script

[Service]
Type=oneshot
ExecStart=/path/to/your/script

em seguida, vá para mymonitor.path para definir o caminho

[Unit]
Description= Triggers the service

[Path]
DirectoryNotEmpty=/path/to/monitor

[Install]
WantedBy=multi-user.target

Se o nome do arquivo .path for o mesmo que o nome do serviço, não será necessário especificar o nome do serviço no arquivo .path.

Baseia-se no Monitorando o acesso a arquivos para leigos

    
por 09.08.2016 / 14:02
5

Você pode usar watch no seu script

watch -n 0.1 ls <your_folder>

Monitora sua pasta e lista tudo nela a cada 0,1 segundo

Drawback

Não é tempo real, portanto, se um arquivo foi criado e excluído em menos de 0,1 segundo, isso não funcionará, watch suporta apenas o mínimo de 0,1 segundos.

    
por 31.08.2017 / 22:15
2

Bash não pode fazer isso facilmente. Você teria basicamente que obter uma lista de todos os arquivos na pasta e, periodicamente, obter uma nova lista e compará-los para ver o que mudou.

O que você está procurando é chamado de inotify. É embutido no kernel do linux e você pode basicamente ficar lá esperando que algo aconteça, no ponto em que o inotify volta e diz 'hey, existe um novo arquivo chamado foobar'

Para conseguir o que você quer, você tem que mudar para algo como perl e usar o Linux :: Inotify2 (python provavelmente suporta inotify também, mas eu sou uma pessoa perl).

    
por 19.11.2011 / 17:33
0

Isso funciona no cygwin e no Linux. Algumas das soluções anteriores que gravam um arquivo farão com que o disco seja espancado. Este scipt não tem esse problema:

SIG=1
SIG0=$SIG
while [ $SIG != 0 ] ; do
 while [ $SIG = $SIG0 ] ; do
   SIG='ls -1 | md5sum | cut -c1-32'
   sleep 10
 done
 SIG0=$SIG
 ls -lrt | tail -n 1
done
    
por 17.11.2016 / 22:24
0

Abaixo está uma versão abreviada do exemplo em stackoverflow que testei e incorporei em um dos meus projetos que exige monitoramento de diretórios específicos.

Var_dir="${1:-/tmp}"
Var_diff_sleep="${2:-120}"
Var_diff_opts="--suppress-common-lines"
Func_parse_diff(){
    _added="$(grep -E '>' <<<"${@}")"
    if [ "${#_added}" != "0" ]; then
        mapfile -t _added_list <<<"${_added//> /}"
        _let _index=0
        until [ "${#_added_list[@]}" = "${_index}" ]; do
            _path_to_check="${Var_dir}/${_added_list[${_index}]}"
            if [ -f "${_path_to_check}" ]; then
                echo "# File: ${_path_to_check}"
            elif [ -d "${_path_to_check}" ]; then
                echo "# Directory: ${_path_to_check}"
            if [ -p "${_path_to_check}" ]; then
                echo "# Pipe: ${_path_to_check}"
            fi
            let _index++
        done
        unset _index
    fi
}
Func_watch_bulk_dir(){
    _current_listing=""
    while [ -d "${Var_dir}" ]; do
        _new_listing="$(ls "${Var_dir}")"
        _diff_listing="$(diff ${Var_dec_diff_opts} <(${Var_echo} "${_current_listing}") <(${Var_echo} "${_new_listing}"))"
        if [ "${_diff_listing}" != "0" ]; then
            Func_parse_diff "${_diff_listing}"
        fi
        _current_listing="${_new_listing}"
        sleep ${Var_diff_sleep}
    done
}

Aqui está um link para um script que usa uma versão modificada acima para descriptografar arquivos automaticamente ou diretórios encontrados em seu ponto de montagem sshfs; o projeto mencionado acima.

    
por 26.11.2016 / 04:47