inotifywait - obtém um nome de arquivo antigo e novo ao renomear

8

Estou procurando uma maneira confiável de detectar a renomeação de arquivos e obter nomes de arquivos antigos e novos. Isto é o que eu tenho até agora:

COUNTER=0;
inotifywait -m --format '%f' -e moved_from,moved_to ./ | while read FILE
do
if [ $COUNTER -eq 0 ]; then
    FROM=$FILE;
    COUNTER=1;
else
    TO=$FILE;
    COUNTER=0;
    echo "sed -i 's/\/$FROM)/\/$TO)/g' /home/a/b/c/post/*.md"
    sed -i 's/\/'$FROM')/\/'$TO')/g' /home/a/b/c/post/*.md
fi
done

Funciona, mas assume que você nunca moverá arquivos para dentro ou para fora da pasta monitorada. Ele também pressupõe que os eventos venham em pares, primeiro movidos_de, depois movidos_para. Não sei se isso sempre é verdade (funciona até agora).

Eu li que o inotify usa um cookie para vincular eventos. O cookie está acessível de alguma forma? Na falta do cookie, pensei em usar registros de data e hora para vincular eventos. Alguma dica sobre como ir e voltar de uma maneira mais confiável?

Conteúdo do script completo .

aBe
fonte

Respostas:

6

Acho que sua abordagem está correta, e rastrear o cookie é uma maneira robusta de fazer isso. No entanto, o único lugar na fonte de inotify-tools (3.14) que cookieé referenciado é no cabeçalho que define o structpara corresponder à API do kernel.

Se você gosta de viver no limite, esse patch ( edição # 72 ) se aplica perfeitamente à 3.14 e adiciona um %cespecificador de formato para o cookie de evento em hexadecimal:

--- libinotifytools/src/inotifytools.c.orig     2014-10-23 18:05:24.000000000 +0100
+++ libinotifytools/src/inotifytools.c  2014-10-23 18:15:47.000000000 +0100
@@ -1881,6 +1881,12 @@
                        continue;
                }

+               if ( ch1 == 'c' ) {
+                       ind += snprintf( &out[ind], size-ind, "%x", event->cookie);
+                       ++i;
+                       continue;
+               }
+
                if ( ch1 == 'e' ) {
                        eventstr = inotifytools_event_to_str( event->mask );
                        strncpy( &out[ind], eventstr, size - ind );

Essa alteração modifica libinotifytools.so, não o inotifywaitbinário. Para testar antes da instalação:

LD_PRELOAD=./libinotifytools/src/.libs/libinotifytools.so.0.4.1 \
  inotifywait  --format="%c %e %f" -m -e move /tmp/test
Setting up watches.
Watches established.
40ff8 MOVED_FROM b
40ff8 MOVED_TO a

Supondo que MOVED_FROM sempre ocorra antes de MOVED_TO (ocorre, vê fsnotify_move()e é uma fila ordenada , embora movimentos independentes possam ser intercalados) em seu script, você armazena em cache os detalhes quando vê uma linha MOVED_FROM (talvez em uma matriz associativa indexada por ID), e execute seu processamento quando vir um MOVED_TO com a metade correspondente das informações.

declare -A cache
inotifywait  --format="%c %e %f" -m -e move /tmp/test |
while read id event file; do
    if [ "$event" = "MOVED_FROM" ]; then
        cache[$id]=$file
    fi
    if [ "$event" = "MOVED_TO" ]; then
        if [ "${cache[$id]}" ]; then
            echo "processing ..."
            unset cache[$id]
        else
            echo "mismatch for $id"
        fi
    fi
done

(Com três threads sendo executados para embaralhar um par de arquivos a cada 10.000 vezes, nunca vi um único evento fora de ordem ou intercalação de eventos. Pode depender do sistema de arquivos e de outras condições, é claro).

mr.spuratic
fonte
1
Bonita. Eu nunca recebi uma resposta tão detalhada e útil antes. Muito obrigado!! Acho que a inclusão do seu patch na versão oficial pode facilitar a criação de ferramentas que ajudam a manter a consistência entre os arquivos de texto (html, css, md, ...) e os recursos referidos (jpg, gif, mp4, ...). Você está enviando uma solicitação de recebimento? :)
aBe
Espero que esse recurso consiga entrar na versão oficial, mas não o tenha bifurcado e não tenho certeza de quando vou encontrar tempo para bifurcar e atualizar todos os comentários (doxygen).
mr.spuratic
Seria muito legal colocar isso no upstream!
precisa