Linux 如何在文件或目录更改时运行 shell 脚本?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4060212/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-03 23:47:44  来源:igfitidea点击:

How to run a shell script when a file or directory changes?

linuxshellinotify

提问by Drew LeSueur

I want to run a shell script when a specific file or directory changes.

我想在特定文件或目录更改时运行 shell 脚本。

How can I easily do that?

我怎样才能轻松做到这一点?

采纳答案by Frédéric Hamidi

回答by Brian Clements

Check out the kernel filesystem monitor daemon

查看内核文件系统监视器守护进程

http://freshmeat.net/projects/kfsmd/

http://freshmeat.net/projects/kfsmd/

Here's a how-to:

这是一个操作方法:

http://www.linux.com/archive/feature/124903

http://www.linux.com/archive/feature/124903

回答by Yoric

As mentioned, inotify-tools is probably the best idea. However, if you're programming for fun, you can try and earn hacker XPs by judicious application of tail -f.

如前所述,inotify-tools 可能是最好的主意。但是,如果您是为了好玩而编程,您可以尝试通过明智地应用tail -f 来赚取黑客 XP 。

回答by slowdog

Here's another option: http://fileschanged.sourceforge.net/

这是另一种选择:http: //fileschanged.sourceforge.net/

See especially "example 4", which "monitors a directory and archives any new or changed files".

特别参见“示例 4”,它“监视目录并存档任何新的或更改的文件”。

回答by VDR

How about this script? Uses the 'stat' command to get the access time of a file and runs a command whenever there is a change in the access time (whenever file is accessed).

这个剧本怎么样?使用 'stat' 命令获取文件的访问时间,并在访问时间发生变化时(每当访问文件时)运行命令。

#!/bin/bash

while true

do

   ATIME=`stat -c %Z /path/to/the/file.txt`

   if [[ "$ATIME" != "$LTIME" ]]

   then

       echo "RUN COMMNAD"
       LTIME=$ATIME
   fi
   sleep 5
done

回答by Dominykas Mostauskis

I use this script to run a build script on changes in a directory tree:

我使用此脚本在目录树中的更改上运行构建脚本:

#!/bin/bash -eu
DIRECTORY_TO_OBSERVE="js"      # might want to change this
function block_for_change {
  inotifywait --recursive \
    --event modify,move,create,delete \
    $DIRECTORY_TO_OBSERVE
}
BUILD_SCRIPT=build.sh          # might want to change this too
function build {
  bash $BUILD_SCRIPT
}
build
while block_for_change; do
  build
done

Uses inotify-tools. Check inotifywaitman pagefor how to customize what triggers the build.

使用inotify-tools. 查看inotifywait手册页了解如何自定义触发构建的内容。

回答by jonatan

Just for debugging purposes, when I write a shell script and want it to run on save, I use this:

只是为了调试目的,当我编写一个 shell 脚本并希望它在保存时运行时,我使用这个:

#!/bin/bash
file="" # Name of file
command="${*:2}" # Command to run on change (takes rest of line)
t1="$(ls --full-time $file | awk '{ print  }')" # Get latest save time
while true
do
  t2="$(ls --full-time $file | awk '{ print  }')" # Compare to new save time
  if [ "$t1" != "$t2" ];then t1="$t2"; $command; fi # If different, run command
  sleep 0.5
done

Run it as

运行它

run_on_save.sh myfile.sh ./myfile.sh arg1 arg2 arg3

Edit: Above tested on Ubuntu 12.04, for Mac OS, change the ls lines to:

编辑:以上在 Ubuntu 12.04 上测试,对于 Mac OS,将 ls 行更改为:

"$(ls -lT $file | awk '{ print  }')"

回答by Dan Garthwaite

Add the following to ~/.bashrc:

将以下内容添加到 ~/.bashrc:

function react() {
    if [ -z "" -o -z "" ]; then
        echo "Usage: react <[./]file-to-watch> <[./]action> <to> <take>"
    elif ! [ -r "" ]; then
        echo "Can't react to , permission denied"
    else
        TARGET=""; shift
        ACTION="$@"
        while sleep 1; do
            ATIME=$(stat -c %Z "$TARGET")
            if [[ "$ATIME" != "${LTIME:-}" ]]; then
                LTIME=$ATIME
                $ACTION
            fi
        done
    fi
}

回答by kenorb

You may try entrtool to run arbitrary commands when files change. Example for files:

您可以尝试使用entr工具在文件更改时运行任意命令。文件示例:

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

or:

或者:

$ ls *.css *.html | entr reload-browser Firefox

or print Changed!when file file.txtis saved:

Changed!file.txt保存文件时打印:

$ echo file.txt | entr echo Changed!


For directories use -d, but you've to use it in the loop, e.g.:

对于目录使用-d,但您必须在循环中使用它,例如:

while true; do find path/ | entr -d echo Changed; done

or:

或者:

while true; do ls path/* | entr -pd echo Changed; done

回答by Is Ma

Suppose you want to run rake testevery time you modify any ruby file ("*.rb") in app/and test/directories.

假设您想在rake test每次修改app/test/目录中的任何 ruby​​ 文件(“*.rb”)时运行。

Just get the most recent modified time of the watched files and check every second if that time has changed.

只需获取所监视文件的最新修改时间,并每秒检查该时间是否已更改。

Script code

脚本代码

t_ref=0; while true; do t_curr=$(find app/ test/ -type f -name "*.rb" -printf "%T+\n" | sort -r | head -n1); if [ $t_ref != $t_curr ]; then t_ref=$t_curr; rake test; fi; sleep 1; done

Benefits

好处

  • You can run any command or script when the file changes.
  • It works between any filesystem and virtual machines (shared folders on VirtualBox using Vagrant); so you can use a text editor on your Macbook and run the tests on Ubuntu (virtual box), for example.
  • 当文件更改时,您可以运行任何命令或脚本。
  • 它适用于任何文件系统和虚拟机(VirtualBox 上使用 Vagrant 的共享文件夹);例如,您可以在 Macbook 上使用文本编辑器并在 Ubuntu(虚拟机)上运行测试。

Warning

警告

  • The -printfoption works well on Ubuntu, but do not work in MacOS.
  • -printf选项在 Ubuntu 上运行良好,但在 MacOS 中不起作用。