Existe um comando como "watch" ou "inotifywait" no Mac?


287

Quero assistir a uma pasta no meu Mac (Snow Leopard) e executar um script (fornecendo o nome do arquivo que acabou de ser movido para uma pasta (como parâmetro ... x.sh "filename")).

Eu tenho um script todo escrito em bash (x.sh) que moverá alguns arquivos e outras coisas na entrada $ 1. Eu só preciso do OSX para me fornecer o nome do arquivo quando novos arquivos / pastas forem movidos / criados em um diretório.

Algum comando desse tipo?


1
Você deve perguntar como o DropBox faz isso, já que provavelmente eles tentaram todas as opções disponíveis.
Jeff Burdges

2
@JeffBurdges Eu não tenho tanta certeza de que seria uma tarefa fácil. No entanto, eu diria que depois de passar por cima da Referência do FSEvents da Apple , seria realmente bobo se o Dropbox não estivesse fazendo uso disso. O fswatchutilitário apresentado como resposta abaixo de fato usa esse método.
Steven Lu

Respostas:


446

fswatch

O fswatch é um pequeno programa que usa a API do Mac OS X FSEvents para monitorar um diretório. Quando um evento sobre qualquer alteração nesse diretório é recebido, o comando shell especificado é executado por/bin/bash

Se você usa o GNU / Linux, o inotifywatch (parte do inotify-toolspacote na maioria das distribuições) fornece funcionalidade semelhante.

Atualização: fswatch agora pode ser usado em várias plataformas, incluindo BSD, Debian e Windows.

Sintaxe / Um exemplo simples

A nova maneira de observar vários caminhos - para as versões 1.xe superiores :

fswatch -o ~/path/to/watch | xargs -n1 -I{} ~/script/to/run/when/files/change.sh

Nota: O número gerado por -oserá adicionado ao final do xargscomando, se não for o -I{}. Se você optar por usar esse número, coloque {}em qualquer lugar do seu comando.

A maneira mais antiga para as versões 0.x :

fswatch ~/path/to/watch ~/script/to/run/when/files/change.sh

Instalação com Homebrew

A partir de 9/12/13, foi adicionado novamente ao homebrew - yay! Portanto, atualize sua lista de fórmulas ( brew update) e tudo o que você precisa fazer é:

brew install fswatch

Instalação sem Homebrew

Digite estes comandos em Terminal.app

cd /tmp
git clone https://github.com/alandipert/fswatch
cd fswatch/
make
cp fswatch /usr/local/bin/fswatch

Se você não possui um ccompilador em seu sistema, pode ser necessário instalar as ferramentas de linha de comando Xcode ou Xcode - ambas gratuitas. No entanto, se for esse o caso, você provavelmente deve verificar o homebrew .

Opções adicionais para a fswatchversão 1.x

Usage:
fswatch [OPTION] ... path ...

Options:
 -0, --print0          Use the ASCII NUL character (0) as line separator.
 -1, --one-event       Exit fsw after the first set of events is received.
 -e, --exclude=REGEX   Exclude paths matching REGEX.
 -E, --extended        Use exended regular expressions.
 -f, --format-time     Print the event time using the specified format.
 -h, --help            Show this message.
 -i, --insensitive     Use case insensitive regular expressions.
 -k, --kqueue          Use the kqueue monitor.
 -l, --latency=DOUBLE  Set the latency.
 -L, --follow-links    Follow symbolic links.
 -n, --numeric         Print a numeric event mask.
 -o, --one-per-batch   Print a single message with the number of change events.
                       in the current batch.
 -p, --poll            Use the poll monitor.
 -r, --recursive       Recurse subdirectories.
 -t, --timestamp       Print the event timestamp.
 -u, --utc-time        Print the event time as UTC time.
 -v, --verbose         Print verbose output.
 -x, --event-flags     Print the event flags.

See the man page for more information.

Suas instruções ou a instalação sem homebrew parecem não funcionar mais. makegera um erro ao não encontrar um makefile. Felizmente, o fswatch agora está no MacPorts, assim sudo port install fswatchfunciona, para aqueles que usam o MacPorts em vez do Homebrew.
Coredumperror

Se você estiver usando um comando com argumentos estáticos (por exemplo, eu estava executando meus testes de unidade no src e nas alterações de teste), isso pode não funcionar para você. Esta pergunta ( stackoverflow.com/questions/25689589/… ) foi a segunda peça que eu precisava.
21815 jskulski

4
Eu ouço você lá fora:fswatch ./ | xargs -I{} cp {} ~/Dropbox/backup/latest/
fionbio

O fswatch é melhor do que ferramentas como entr ou when_changed, que apresentam alguns erros ao lidar com o diretório .git. O fswatch é muito mais profissional. Simplesmente, você apenas fswatch .monitorará o diretório atual.
anônimo

Eu sugeriria fswatch -0 -v -o /path/to/watched/files | xargs -0 -n 1 -I {} [your command]com -0para NULLs. Este funciona para mim para menos compilação
boldnik

95

Você pode usar o launchd para esse fim. Launchd pode ser configurado para iniciar automaticamente um programa quando um caminho de arquivo é modificado.

Por exemplo, o seguinte launchd config plist iniciará o programa /usr/bin/loggerquando a pasta da área de trabalho da minha conta de usuário for modificada:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>logger</string>
    <key>ProgramArguments</key>
    <array>
        <string>/usr/bin/logger</string>
        <string>path modified</string>
    </array>
    <key>WatchPaths</key>
    <array>
        <string>/Users/sakra/Desktop/</string>
    </array>
</dict>
</plist>

Para ativar o config plist, salve-o na pasta LaunchAgents na sua pasta Library como "logger.plist".

No shell, você pode usar o comando launchctlpara ativar o logger.plist executando:

$ launchctl load ~/Library/LaunchAgents/logger.plist

A pasta da área de trabalho agora está sendo monitorada. Sempre que for alterado, você verá uma saída no system.log (use Console.app). Para desativar o logger.plist, execute:

$ launchctl unload ~/Library/LaunchAgents/logger.plist

O arquivo de configuração acima usa a WatchPathsopção Como alternativa, você também pode usar a QueueDirectoriesopção Veja a página de manual do launchd para mais informações.


1
existe uma maneira de monitorar a alteração no conteúdo do arquivo e no caminho do arquivo?
Cam

2
Acho que não. Você pode usar o opensnoop para esse fim.
Sahara

1
Consegui fazer isso funcionar, mas, quando mudei /usr/bin/loggercom o meu script Bash e removi a "<string>path modified</strong>"entrada, não consegui encontrar nenhuma maneira de meu script bash saber qual arquivo na minha área de trabalho foi modificado - apenas que o evento ocorreu. Eu tentei olhar para $0, $1e só tem o próprio nome do script, notando passado para ele.
Volomike 23/03

Além disso, essa coisa entra em loop quando detecta uma alteração, em vez de apenas iniciar (e parar) quando detecta uma alteração? Prefiro que funcione sob demanda, não continue executando em um loop, dizendo-me que, por exemplo, há dois dias, algo mudou na minha área de trabalho, escrevendo isso no log várias vezes. Então, precisamos usar algum tipo de opção de intervalo nesta lista?
Volomike 23/03

Grande trabalho e explicação
ChenSmile

37

O vigia do Facebook , disponível via Homebrew, também parece legal. Ele também suporta filtragem:

Essas duas linhas estabelecem uma vigilância em um diretório de origem e, em seguida, configuram um gatilho chamado "buildme" que executará uma ferramenta chamada "minify-css" sempre que um arquivo CSS for alterado. A ferramenta receberá uma lista dos nomes de arquivos alterados.

$ watchman watch ~/src

$ watchman -- trigger ~/src buildme '*.css' -- minify-css

Observe que o caminho deve ser absoluto.


1
Esta é de longe a melhor ferramenta.
BentOnCoding

1
Este é um pequeno programa muito bom: os documentos são ótimos, não abrem um loop infinito (que é o que o fswatch parece fazer) e se lembram dos relógios que você criou após a reinicialização e os reinicia automaticamente.
Brad

21

Você pode dar uma olhada (e talvez expandir) minha pequena ferramenta kqwait. Atualmente, ele fica parado e aguarda um evento de gravação em um único arquivo, mas a arquitetura kqueue permite o empilhamento hierárquico de eventos ...


Funciona até agora no leão da montanha. Muito agradável!
Scott

Então, isso é realmente incrível. Corri para um pequeno problema com fswatch(o que também é bom, já que é um invólucro tão leve que também pode ser modificado para fazer a coisa certa, tenho certeza) onde ele disparava ao executar coisas como git status(que na verdade é executado toda vez que o zsh O prompt é renderizado na minha máquina ...) que na verdade meio que estraga esse script elaborado que eu tenho, criando um loop infinito de feedback. O kqwait, no entanto, fornece as informações sobre o arquivo alterado e não é acionado git status. Eu preciso que ele seja acionado para gravar.
Steven Lu

2
$ brew install kqwait && while true; do kqwait doc/my_file.md; make; done
Joshua Cook

15

watchdog é uma API python multiplataforma para monitorar arquivos / diretórios e possui uma ferramenta "truques" embutida que permite disparar ações (incluindo comandos do shell) quando ocorrem eventos (incluindo novo arquivo adicionado, arquivo removido e arquivo alterado).


7

Isso é apenas para mencionar entr como uma alternativa no OSX para executar comandos arbitrários quando os arquivos mudam. Acho simples e útil.



3

Editar: fsw foi mesclado fswatch. Nesta resposta, qualquer referência a fswdeve agora lerfswatch .

Eu escrevi uma fswatchsubstituição em C ++ chamada fswque apresenta várias melhorias:

  • É um projeto do GNU Build System que se baseia em qualquer plataforma suportada (OS X v.> = 10.6) com

    ./configure && make && sudo make install
    
  • Vários caminhos podem ser transmitidos como argumentos diferentes:

    fsw file-0 ... file-n 
    
  • Ele despeja um registro detalhado com todas as informações do evento, como:

    Sat Feb 15 00:53:45 2014 - /path/to/file:inodeMetaMod modified isFile 
    
  • Sua saída é fácil de analisar, para que a fswsaída possa ser canalizada para outro processo.

  • A latência pode ser personalizada com -l, --latency .
  • Os sinalizadores de eventos numéricos podem ser escritos em vez dos textuais com -n, --numeric .
  • O formato da hora pode ser personalizado usando strftimecadeias de formato com -t, --time-format.
  • A hora pode ser a hora local da máquina (por padrão) ou a hora UTC com -u, --utc-time.

Obtendo fsw:

fswestá hospedado no GitHub e pode ser obtido clonando seu repositório:

    git clone https://github.com/emcrisostomo/fsw

Instalando o fsw:

fsw pode ser instalado usando os seguintes comandos:

    ./configure && make && sudo make install

Outras informações:

Também escrevi um post introdutório no blog, onde você pode encontrar alguns exemplos sobre como fswfunciona.


2

As ações de pasta do Apple OSX permitem automatizar tarefas com base nas ações executadas em uma pasta.


9
Sim, eu sei, eu tentei usar isso várias vezes, nunca consegui fazer funcionar com sucesso, você poderia me dar um exemplo?
Mint

1
Isso é um link, não uma resposta
Dan Rosenstark 02/02/19

2

Minha bifurcação do fswatch fornece a funcionalidade de saídainotifywait -m um pouco menos (sem espera, mais! Eu tenho muito mais problemas no Linux com inotifywait...) saída compatível com análise.

É uma melhoria em relação ao original fswatch porque envia o caminho real do arquivo alterado por STDOUT, em vez de exigir que você forneça um programa que ele bifurca.

Tem sido sólido como base de uma série de scripts bash assustadores que eu uso para automatizar coisas.

(isso é fora de tópico) inotifywaitno Linux, por outro lado, exige muitos elogios e ainda não descobri uma boa maneira de gerenciá-lo, embora eu ache que algo baseado node.jspossa ser o bilhete.


1
Certo, garfo de fswatch. É que no Homebrew?
fatuhoku 4/09/2013

1
A resposta é não; mas eles estão trabalhando nisso . Para instalá-lo muito rapidamente apenas brew install https://raw.github.com/mlevin2/homebrew/116b43eaef08d89054c2f43579113b37b4a2abd3/Library/Formula/fswatch.rb
fatuhoku

1

Eu tenho um GIST para isso e o uso é bastante simples

watchfiles <cmd> <paths...>

Para ilustrar, o seguinte comando ecoará Hello Worldsempre que file1OU file2mudar; e a verificação do intervalo padrão é de 1 segundo

watchfiles 'echo Hello World' /path/to/file1 /path/to/file2 

Se eu quiser verificar a cada 5 segundos, posso usar a -tbandeira

watchfiles -t 'echo Hello World' /path/to/file1 /path/to/file2 
  • -vativa o verbosemodo que mostra informações de depuração
  • -qfaz watchfilesexecutar silenciosamente ( #será mostrado para que o usuário possa ver o programa em execução)
  • -qqfaz watchfilesexecutar completamente silenciosamente
  • -h mostra a ajuda e o uso

https://gist.github.com/thiagoh/5d8f53bfb64985b94e5bc8b3844dba55


0

Acabei fazendo isso no macOS. Tenho certeza de que isso é terrível de várias maneiras:

#!/bin/sh
# watchAndRun
if [ $# -ne 2 ]; then
    echo "Use like this:"
    echo "   $0 filename-to-watch command-to-run"
    exit 1
fi
if which fswatch >/dev/null; then
    echo "Watching $1 and will run $2"
    while true; do fswatch --one-event $1 >/dev/null && $2; done
else
    echo "You might need to run: brew install fswatch"
fi

Eu não conseguia descobrir a sintaxe fswatch sem o tempo. O que é irritante e dificulta a parada do script.
Dan Rosenstark 02/02/19

0

Se você deseja usar o NodeJS, pode usar um pacote chamado chokidar (ou chokidar-cli, na verdade) para assistir e, em seguida, usar rsync(incluído no Mac):

Comando Rsync:

$ rsync -avz --exclude 'some-file' --exclude 'some-dir' './' '/my/destination'

Chokidar cli (instalado globalmente via npm):

chokidar \"**/*\" -c \"your-rsync-command-above\"


-3

Aqui está uma alternativa simples de linha única para usuários que não têm o watch comando que desejam executar um comando a cada 3 segundos:

while :; do your-command; sleep 3; done

É um loop infinito que é basicamente o mesmo que fazer o seguinte:

watch -n3 your-command


3
NÃO é o mesmo que usar uma biblioteca que escuta eventos do sistema de arquivos. Se no seu exemplo, your-commanda E / S do disco é uma leitura / gravação garantida do disco a cada 3 segundos - ou 10.800 vezes a cada hora. Usando eventos do sistema de arquivos que você seria garantido que I / O (e outras operações caros) só acontecem quando você altera um arquivo (que geralmente é apenas um par de vezes por hora.)
Noah Sussman

É verdade e é bom considerar. Eu geralmente preciso fazer watchcoisas por períodos temporários para ver o que algo está fazendo. Não uso minha técnica mencionada para aplicativos de produção ou algo assim. Por exemplo, eu gostaria de ver o progresso de dd, e minha técnica faz isso acontecer (substituindo your-commandconforme apropriado para enviar o sinal apropriado dd).
trusktr
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.