Control the set of files for changes and execute a command on them when they do it

I mean the interface (command line):

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

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

For instance:

 > 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 am not tied to this interface. I will add my script that will do this as an answer and see if anyone has the best or ways to improve it.

+4
source share
4 answers
 #!/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; } 
+2
source

Please check inotify tools .

+1
source

I just found this every_change script written in perl, which is very similar to the one I posted in my answer.

This script kicks ass for code development. It watches the file and runs it (or something else) every time it changes. Write your code in one window and see how it automatically runs in another.

So basically it does something every time the file changes.

+1
source

You can use entr , for example

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

Unfortunately, you cannot check which file has been modified, but using rsync -u will automatically skip files that have not been modified.

Here is a second example:

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

or just use make , for example

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

To view the change catalog, use the -d , enclosed inside the shell loop, for example:

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

All Articles