Script para monitorar a pasta para novos arquivos?

127

Como detectar novos arquivos em uma pasta com um script ? Gostaria de processar os arquivos assim que eles forem criados na pasta. Isso é possível ou preciso agendar um script com que verifique se há novos arquivos a cada minuto ou mais?

ihatetoregister
fonte
11
Você removerá os arquivos da pasta depois que eles forem processados?
Ztank1013

Respostas:

151

Você deve considerar o uso 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 inotify-toolspacote. A partir da versão 3.13 (atual no Ubuntu 12.04) inotifywaitincluirá o nome do arquivo sem a opção -f. Versões mais antigas podem precisar ser coagidas. O que é importante observar é que a -eopção inotifywaité a melhor maneira de fazer a filtragem de eventos. Além disso, seu readcomando pode atribuir a saída posicional em várias variáveis ​​que você pode optar por usar ou ignorar. Não há necessidade de usar grep / sed / awk para pré-processar a saída.

enzotib
fonte
11
Ótimo! A inotifywaitera exatamente o que eu queria.
Ihatetoregister
2
Só quero atualizar isso. Você não precisa do awk para conseguir isso. você pode filtrar os eventos com '-e create' e obter apenas o nome do arquivo executando '-f% f' ou o caminho completo usando '-f% w% f'. Portanto, a primeira linha do script acima se torna: inotifywait -m / path -f% w% f -e create |
Lugoues 03/03
2
@ Lugoues e agora, quando você tenta usar -f você recebe The '--filename' option no longer exists. The option it enabled in earlier versions of inotifywait is now turned on by default.Então, você só precisa fazer inotifywait -m /path -e create |isso, vou tentar editar esta resposta.
precisa saber é o seguinte
11
Agora também há uma ferramenta portátil para ela chamada fswatch. Eu não escrevi, mas é de código aberto e eu o uso.
11
O @Wender inotfiywait gera 3 informações em uma única linha quando acionado. O bash 'read' incorporado lê a linha de entrada e atribui cada uma das três informações a uma variável. Assim, a primeira parte é atribuída ao caminho da variável, a segunda à ação e a terceira ao arquivo. Depois de atribuir valores a essas variáveis, elas estarão disponíveis para serem usadas posteriormente (como na linha de eco). Mais informações: tldp.org/LDP/Bash-Beginners-Guide/html/sect_08_02.html
Tim
26

Eu prefiro incron, pois é mais fácil de gerenciar. Essencialmente, é um serviço que aproveita inotifye você pode definir configurações para executar ações com base nas operações de alteração de arquivo.

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: http://www.cyberciti.biz/faq/linux-inotify-examples-to-replicate-directories/

rynop
fonte
24

Acabei de preparar isso e não vejo grandes problemas com isso, 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 arquivo não demorar muito, você não deve perder nenhum novo arquivo. Você também pode ter as atividades em segundo plano ... Não é à prova de balas, mas serve a alguns propósitos sem ferramentas externas, como inotify.

Michael Sacchi
fonte
Boa pegada. Eu o melhorei um pouco para suportar espaços nos nomes de arquivos.
Michael Sacchi
Absolutamente. Esse é o caminho a percorrer. Não tenho muita certeza de por que segui esse caminho, uso -exec rotineiramente.
Michael Sacchi
não é em tempo real. em tempo real é sempre melhor
Farhan
3
Melhor solução se inotifynão estiver disponível. Eu adicionaria -type fpara filtrar apenas os arquivos. Caso contrário, a pasta também será retornada.
Xiao Peng - ZenUML.com
Sim - a -f filenameopção é ótima. Portanto, a única questão restante é como fazer isso iniciar na reinicialização. Vou usar isso com minha planta solar para os.system("ssh me@mysystem ' ( touch /home/me/alarms/low24 ) '")que a criação desse arquivo faça com que o computador mestre use espeake anuncie a baixa tensão. Ele já me envia um e-mail, mas como meu sistema já fala as horas no início da hora, ele tem todo o resto. askubuntu.com/questions/977613/...
SDsolar
19

Você pode usar watchno seu script

watch -n 0.1 ls <your_folder>

Monitora sua pasta e lista tudo a cada 0,1 segundos

Recua

Não é em tempo real; portanto, se um arquivo foi criado e excluído em menos de 0,1 segundo, isso não funcionaria, watchapenas suportaria no mínimo 0,1 segundo.

CiganoCosmonauta
fonte
Era exatamente disso que eu estava tentando lembrar! Muito obrigado!!
Joabe Lucena 22/03
9

Estou assumindo que a pasta de destino (vou chamá-la isemptyapenas por conveniência) está vazia e você está esperando um ou mais arquivos serem descartados lá.

Você pode usar o seguinte comando:

ls -1A isempty | wc -l

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

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

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

Obviamente, a do_somethingfunção terá que manipular o (s) arquivo (s) dentro da isemptypasta e 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 do_somethingação se a pasta não estiver vazia, é claro:

* * * * *     if [ $(ls -1A isempty | wc -l) -gt 0 ] ; then do_something ; fi
ztank1013
fonte
Esta solução funciona para sistemas de arquivos remotos montados. Os desenvolvedores da inotify-tools estão trabalhando em fusíveis (ou estavam em meados de 2014).
Rondo
3
Você nunca deve usar lspara scripts. Use findou globbing simples: mywiki.wooledge.org/ParsingLs
andsens 28/11/16
6

Se você deseja detectar novos arquivos, processe-os e, no final, exclua os arquivos prosseguidos, você pode usar systemd.path . Este método baseia-se em inotify. Há uma opção DirectoryNotEmpty, para que o systemd possa executar seu script sempre que detectar qualquer arquivo no diretório. Você deve se lembrar que ele funcionará apenas se você puder excluir os arquivos prosseguidos 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 monitoramento de acesso a arquivos para manequins

Dawid Wolski
fonte
4

entr

Usar entré a nova maneira de fazer isso (é multiplataforma). A nota entrnão usa sondagem, o que oferece uma enorme vantagem sobre muitas das alternativas.

Usa kqueue(2)ou inotify(7)para evitar pesquisas. entrfoi escrito para tornar o feedback rápido e os testes automatizados naturais e completamente comuns.

No BSD, ele usa pledge(2)

Você pode instalá-lo com

apt-get install entr
dnf install entr

Você pode rastrear um diretório para novas adições usando

while $(true); do
  # echo ./my_watch_dir | entr -dnr echo "Running trigger..."
  echo ./my_watch_dir | entr -dnr ##MY COMMAND##
done;

Opções explicadas (nos documentos),

  • -d Acompanhe os diretórios dos arquivos regulares fornecidos como entrada e saia se um novo arquivo for adicionado. Esta opção também permite que os diretórios sejam especificados explicitamente. Arquivos com nomes começando com '.' são ignorados.
  • -nExecute no modo não interativo. Nesse modo, o entr não tenta ler o TTY ou alterar suas propriedades.
  • -r Recarregue um processo filho persistente. Como no modo de operação padrão, um utilitário que termina não é executado novamente até que um evento do sistema de arquivos ou do teclado seja processado. SIGTERMé usado para finalizar o utilitário antes de ser reiniciado. Um grupo de processos é criado para impedir que scripts de shell ocultem sinais. entraguarda a saída do utilitário para garantir que recursos como soquetes foram fechados. O controle do TTY não é transferido para o processo filho.
Evan Carroll
fonte
2

O Bash não pode fazer isso facilmente. Você precisaria basicamente 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 inotify. Ele está embutido no kernel do linux e você pode basicamente ficar sentado esperando que algo aconteça. Nesse momento, o inotify volta e diz 'ei, existe um novo arquivo chamado foobar'

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

Patrick
fonte
0

Isso funciona no cygwin e Linux. Algumas das soluções anteriores que escrevem um arquivo farão com que o disco seja danificado. 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
user1186515
fonte
0

Abaixo está uma versão resumida do exemplo no stackoverflow que eu testei e incorporei em um dos meus projetos que requer 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 automaticamente arquivos ou diretórios encontrados em seu ponto de montagem sshfs; o projeto mencionado acima.

S0AndS0
fonte