Мониторинг набора файлов на предмет изменений и выполнение команды для них, когда они делают - PullRequest
4 голосов
/ 25 декабря 2008

Интерфейс (командной строки), который я имею в виду, выглядит так:

watching FILE+ do COMMAND [ARGS] (and COMMAND [ARGS])*

Где любое вхождение "{}" в COMMAND заменяется именем файла, который изменился. И обратите внимание, что "do" и "and" являются ключевыми словами.

Например:

> watching foo.txt bar.txt do scp {} somewhere.com:. and echo moved {} to somewhere

Или:

> watching foo.c do gcc foo.c and ./a.out

Хотя я не привязан к этому интерфейсу. Я добавлю свой сценарий, который делает это в качестве ответа, и посмотрю, есть ли у кого-нибудь что-нибудь лучше или способы улучшить его.

Ответы [ 4 ]

2 голосов
/ 25 декабря 2008
#!/usr/bin/perl
# Run some commands whenever any of a set of files changes (see USAGE below).
# Example:
# ./watching.pl foo.txt bar.txt do scp foo.txt remote.com:. and cat bar.txt
# To only do something to the file that changed, refer to it as {}.

$| = 1;  # autoflush

my $p = position("do", @ARGV); # position of 1st occurrence of "do" in @ARGV.
if (@ARGV < 3 || $p == -1 || !($p >= 1 && $p < $#ARGV)) {
  die "USAGE: watching FILE+ do COMMAND [ARGS] (and COMMAND [ARGS])*\n";
}

my $cmdstr = join(' ', splice(@ARGV, $p+1));  # grab stuff after the "do"
my @cmds = split(/\s+and\s+/, $cmdstr);
pop(@ARGV);  # remove the "do" on the end.
my @targets = @ARGV;
print "Watching {", join(' ', @targets), "} do (", join('; ', @cmds), "):\n";

# initialize the %last hash for last mod time of each file.
for my $t (@targets) {
  ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,
   $atime,$mtime,$ctime,$blksize,$blocks) = stat($t);
  $last{$t} = $mtime;
}

my $i = 1;
while(1) {
  if($i % (45*60) == 0) { print "."; }

  for my $t (@targets) {
    ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,
     $atime,$mtime,$ctime,$blksize,$blocks) = stat($t);

    if ($mtime != $last{$t}) {
      print "\nCHANGE DETECTED TO $t\n";
      for (@cmds) { my $tmp = $_; $tmp =~ s/\{\}/$t/g; system($tmp); }
      $last{$t} = $mtime;
    }
  }
  sleep(1);
  $i++;
}


# Call like so: position($element, @list).
sub position {
  my $x = shift;
  if(@_==0) { return -1; }
  if($x eq $_[0]) { return 0; }
  shift;
  my $p = position($x,@_);
  if($p==-1) { return -1; }
  return 1+$p;
}
1 голос
/ 27 декабря 2008

Я только что нашел every_change скрипт , написанный на Perl, очень похожий на тот, который я написал в своем ответе.

Этот скрипт пинает задницу для разработки кода. Просматривает файл и запускает его (или что-то еще) каждый раз, когда он изменяется. Напишите свой код в одном окне и посмотрите, как он автоматически выполняется в другом.

Так что в основном он что-то делает каждый раз, когда файл изменяется.

1 голос
/ 26 декабря 2008

Пожалуйста, проверьте inotify инструменты .

0 голосов
/ 06 июля 2016

Вы можете использовать entr, например,

ls foo.txt bar.txt | entr sh -c 'rsync -vuar *.txt somewhere.com:. && echo Updated'

К сожалению, вы не можете проверить, какой файл был изменен, но использование rsync -u автоматически пропустит файлы, которые не были изменены.

Вот второй пример:

ls foo.c | entr sh -c 'gcc foo.c && ./a.out'

или просто используйте make, например,

ls -d * | entr sh -c 'make && make test'

Чтобы посмотреть каталог на наличие изменений, используйте параметр -d, заключенный в цикл оболочки, например ::

while true; do find path/ | entr -d do_stuff; done
...