Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
482 views
in Technique[技术] by (71.8m points)

scripting - Monitor a set of files for changes and execute a command on them when they do

The (command line) interface I have in mind is like so:

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

Where any occurrence of "{}" in COMMAND is replaced with the name of the file that changed. And note that "do" and "and" are keywords.

For example:

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

Or:

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

I'm not wedded to that interface though. I'll add my script that does that as an answer and see if anyone has anything better or ways to improve it.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)
#!/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])*
";
}

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

# 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 "
CHANGE DETECTED TO $t
";
      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;
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...