Command line 监视一组文件的更改,并在更改时对其执行命令

Command line 监视一组文件的更改,并在更改时对其执行命令,command-line,scripting,file,sysadmin,Command Line,Scripting,File,Sysadmin,我想到的(命令行)界面如下: watching FILE+ do COMMAND [ARGS] (and COMMAND [ARGS])* 其中,命令中出现的任何“{}”将替换为更改的文件名。请注意,“do”和“和”是关键字 例如: > watching foo.txt bar.txt do scp {} somewhere.com:. and echo moved {} to somewhere 或: 不过,我并不热衷于这个界面。我将添加我的脚本作为答案,看看是否有人有更好的方法或改

我想到的(命令行)界面如下:

watching FILE+ do COMMAND [ARGS] (and COMMAND [ARGS])*
其中,
命令
中出现的任何“
{}
”将替换为更改的文件名。请注意,“
do
”和“
”是关键字

例如:

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

不过,我并不热衷于这个界面。我将添加我的脚本作为答案,看看是否有人有更好的方法或改进方法。

#/usr/bin/perl
#!/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;
}
#每当一组文件中的任何一个发生更改时,运行一些命令(请参见下面的用法)。 #例如: #./watching.pl foo.txt bar.txt do scp foo.txt remote.com:。和cat bar.txt #要仅对更改的文件执行某些操作,请将其称为{}。 $| = 1; # 自动冲洗 我的$p=位置(“do”,@ARGV);#@ARGV中第一次出现“do”的位置。 如果(@ARGV<3 | |$p==-1 | |!($p>=1&&$p<$| ARGV)){ die“用法:监视文件+do命令[ARGS](和命令[ARGS])*\n; } my$cmdstr=join(“”,splice(@ARGV,$p+1));#在“做”之后抓东西 my@cmds=split(/\s+和\s+/,$cmdstr); 流行音乐(@ARGV);#移除末端的“do”。 我的@targets=@ARGV; 打印“监视{”,加入(“”,@targets),“}do(“”,加入(“;”,@cmds),”:\n”; #初始化每个文件上次修改时间的%last哈希。 我的$t(@targets){ ($dev、$ino、$mode、$nlink、$uid、$gid、$rdev、$size、, $atime、$mtime、$ctime、$blksize、$blocks)=stat($t); $last{$t}=$mtime; } 我的$i=1; 而(1){ 如果($i%(45*60)==0{print.”;} 我的$t(@targets){ ($dev、$ino、$mode、$nlink、$uid、$gid、$rdev、$size、, $atime、$mtime、$ctime、$blksize、$blocks)=stat($t); 如果($mtime!=$last{$t}){ 打印“\n检测到的更改为$t\n”; 对于(@cmds){my$tmp=$\;$tmp=~s/\{\}/$t/g;系统($tmp);} $last{$t}=$mtime; } } 睡眠(1); $i++; } #像这样调用:position($element,@list)。 子位置{ 我的$x=班次; 如果(@==0){return-1;} 如果($x eq$u0]){返回0;} 转移; 我的$p=位置($x,@u;); 如果($p==-1){return-1;} 返回1+p美元; }
请检查。

我刚刚发现这是用perl编写的,与我在回答中发布的内容非常相似

这个脚本对于代码开发非常有用。监视文件并在每次更改时运行它(或其他内容)。在一个窗口中编写代码,并观察它在另一个窗口中自动执行

因此,基本上每次文件更改时,它都会执行某些操作。

您可以使用,例如

不幸的是,您无法检查哪个文件已更改,但使用
rsync-u
将自动跳过未更改的文件

下面是第二个例子:

ls foo.c | entr sh -c 'gcc foo.c && ./a.out'
或者简单地使用
make
,例如

ls -d * | entr sh -c 'make && make test'
要查看目录的更改,请使用包装在shell循环中的
-d
参数,例如:

while true; do find path/ | entr -d do_stuff; done
ls -d * | entr sh -c 'make && make test'
while true; do find path/ | entr -d do_stuff; done