Oglądaj system plików w czasie rzeczywistym na OS X i Ubuntu

11

Szukam narzędzia CLI, które obejrzy katalog i wypluje nazwy plików, które zmieniają się w czasie rzeczywistym.

some_watch_command /path/to/some/folder | xargs some_callback

Jestem świadomy inotify( inotify-tools?) I wydaje się, że jest to, czego potrzebuję, ale potrzebuję czegoś, co jest zarówno Linux (w moim przypadku Ubuntu), jak i OSX.

Nie musi być błyskawiczny, ale musi się uruchamiać po zmianach (w ciągu sekundy jest to rozsądne). Ponadto niekoniecznie potrzebuję dokładnie wspomnianego powyżej programu CLI. Jeśli istnieje jakaś podstawowa technologia i jest łatwa do skryptowania na obu platformach, to też byłoby świetnie.

Adrian Schneider
źródło
1
Podoba mi się fswatchOS X, który znalazłem w pytaniu oznaczonym jako duplikat - superuser.com/questions/445907/…
cwd

Odpowiedzi:

11

OS X zwykle używa do tego zadania akcji folderów lub uruchomionych .

Jedynym znanym mi narzędziem międzyplatformowym jest API watchdog dla Pythona (dostępne dla systemów OS X i Linux). Zainstaluj przez pip(lub easy_install)

pip install watchdog

Jest wyposażony w watchmedonarzędzie wiersza poleceń, które umożliwia uruchamianie poleceń powłoki w przypadku zdarzeń systemowych. Sprawdź ogólną składnię za pomocąwatchmedo --help

Oto krótki przykład, w którym można łatwo zmodyfikować polecenie i ścieżkę wyróżnioną pogrubioną czcionką:

watchmedo shell-command \
    --recursive \
    --command = ' echo "$ {watch_src_path}" ' \
     / some / folder

Spowodowałoby to po prostu wyrzucenie ścieżek do wszystkich zmienionych plików lub folderów, umożliwiając watchmedoprzesyłanie danych wyjściowych potoku do innego polecenia powłoki.

slhck
źródło
Wygląda na to, że akcje folderów mają pewne ograniczenia (i są trudne do przetestowania bez OSX), ale watchmedodla mnie działa idealnie. Dzięki!
Adrian Schneider
2

Poprawiłem kilka skryptów Ruby, z którymi się spotkałem, aby robić dokładnie to, czego szukasz. Oto kod Ruby:

#!/usr/bin/ruby
# Inspired by http://vikhyat.net/code/snippets/#watchfile

# How to use:
# This script takes two paramaters:  a folder and a shell command
# The script watches for when files in the folder are changed.  When they are, the shell command executes
# Here are some shortcuts you can put in the shell script:
# %F = filename (with extension)
# %B = base filename (without extension)


unless ARGV.length == 2
  puts "\e[32m    Usage: \e[0mruby OnSaveFolder.rb 'folder' 'command'"
  exit
end

require 'digest/md5'
require 'ftools'

$md5 = ''
$directory = File.expand_path(ARGV[0])
$contents = `ls #{$directory}`
$contentsList = $contents.split("\n")
$fileList = []


Dir.chdir($directory)

for i in $contentsList
  if ( File.file?(File.expand_path(i)) == true)
    $fileList.push(i)
  end
end

$processes = []

def watch(file, timeout, &cb)
  $md5 = Digest::MD5.hexdigest(File.read(file))
  loop do
    sleep timeout
    if ( temp = Digest::MD5.hexdigest(File.read(file)) ) != $md5
      $md5 = temp
      cb.call(file)
    end
  end
end

puts "\e[31m Watching files in folder \e[34m #{$directory}"
puts "\e[32m    Press Control+C to stop \e[0m"

for i in $fileList
  pid = fork do
    $num = 0
    $filePath = File.expand_path(i)

    watch i, 1 do |file|
      puts "\n     #{i} saved"

      $command = ARGV[1].dup
      if ( ARGV[1].include?('%F') )
        $command = $command.gsub!('%F', i)
      end
      if ( ARGV[1].include?('%B') )
        $command = $command.gsub!('%B', File.basename(i, '.*'))
      end

      $output = `#{$command}`
      if ( $output != '')
        puts "\e[34m     #{$command}\e[31m output: \e[0m"
        puts $output
      end
      puts "\e[34m     #{$command}\e[31m finished \e[0m (#{$num}, #{Time.now})\n"
      $num += 1

    end
  end
  $processes.push(pid)
end

Process.wait(pid)

for i in $processes
  `kill #{i}`
end

Nazwałem ten skrypt „OnSaveFolder.rb”. Wymaga dwóch parametrów: folderu, w którym chcesz obserwować zmiany, oraz kodu bash, który chcesz uruchomić, gdy nastąpiła zmiana. Na przykład,

ruby OnSaveFolder.rb '/home/Movies' 'echo "A movie has been changed!"'

Mam nadzieję, że to pomoże! Przekonałem się, że Ruby działa bardzo dobrze w tego typu rzeczach i jest domyślnie zainstalowany w systemie OS X.

speedofmac
źródło
Daj temu szansę, ale trochę trudny do ulepszenia bez żadnego rubinowego tła. W każdym razie dzięki!
Adrian Schneider
to jest świetne. jakiś pomysł, jak sprawić, by rekurencyjnie oglądało foldery poniżej?
Nate Flink,
Jeśli nie obchodzi mnie wykonanie polecenia zmiany, czy byłoby to wieloplatformowe, czy tylko uniksowe? I czy to rzeczywiście czas rzeczywisty? Niektórzy obserwatorzy plików mają niedorzeczne opóźnienie (minuty).
Automatico,
2

Można umieścić lsofw watchpoleceniu i go aktualizować co <s>sekund:

watch -n <s> lsof

i uruchom to z dowolnym filtrem, takim jak oglądanie pid1, pid2, pid3 i ignorowanie pid4

lsof -p "pid1,pid2,pid3,^pid4"

Jeśli to nie wystarczy, zawsze możesz napisać własne filtry za pomocą grep.

W przypadku systemu OS X zobacz odpowiedzi na to pytanie .

Dzień D
źródło
0

entr jest miły. Możesz filtrować dokładnie takie pliki, które chcesz oglądać, w ten sposób.

find . -name '*.py' | entr python runTests.py

Jeśli chcesz, aby monitorował tylko niektóre pliki w katalogu, możesz spreparować swoje findpolecenie, aby zwracało tylko pliki, które chcesz obejrzeć.

Łatwiej jest go skonfigurować niż fswatch.

Christian Long
źródło