Bash脚本,监视文件夹,执行命令

时间:2011-06-25 01:39:26

标签: macos bash shell

我正在尝试创建一个带有2个参数的bash脚本:目录和命令。我需要查看此目录以进行更改,并且当某些内容发生更改时,我需要执行该命令。我真的很喜欢用bash编写脚本而且我不确定我在做什么,所以对我很轻松。我也在Mac上,而不是linux。任何指针或外部资源都会有很大帮助。我知道有很多人在互联网上尝试这一点,似乎没有人能够做到这一点。我真的想模仿SASS的手表功能。

#!/bin/bash

#./watch.sh $PATH $COMMAND

DIR=$1  

ls -l $DIR > $DIR/.begin
#this does not work
DIFFERENCE=$(diff .begin .end)

if [ $DIFFERENCE = '\n']; then
    #files are same
else
    $2
fi 

ls -l $DIR > $DIR/.end

12 个答案:

答案 0 :(得分:37)

连续递归监视文件夹(md5)并在更改时执行命令:

daemon() {
    chsum1=""

    while [[ true ]]
    do
        chsum2=`find src/ -type f -exec md5 {} \;`
        if [[ $chsum1 != $chsum2 ]] ; then           
            compile
            chsum1=$chsum2
        fi
        sleep 2
    done
}

在我的OS X上运行,因为我没有digest

在Linux上,您可以使用md5sum替代md5命令。

答案 1 :(得分:10)

方法1:

#!/bin/sh

check() {
    dir="$1"
    chsum1=`digest -a md5 $dir | awk '{print $1}'`
    chsum2=$chsum1

    while [ $chsum1 -eq $chsum2 ]
    do
        sleep 10
        chsum2=`digest -a md5 $dir | awk '{print $1}'`
    done

    eval $2
}

check $*

此脚本包含两个参数[directory,command]。脚本每隔10秒执行check()以查看文件夹已更改。如果没有,它就会睡觉并重复循环。

如果文件夹已更改,则eval是您的命令。

方法2:
使用cron监视文件夹。

您必须安装incron:

 sudo apt-get install incron

然后你的脚本会看起来像这样:

#!/bin/bash
eval $1

(您不需要指定文件夹,因为它将是cron监视指定目录的工作)

可在此处找到完整的工作示例:

  

http://www.errr-online.com/index.php/2011/02/25/monitor-a-directory-or-file-for-changes-on-linux-using-inotify/

答案 2 :(得分:10)

我不敢相信没人发布这个。

首先确保已安装 inotify-tools

然后像这样使用它们:

logOfChanges="/tmp/changes.log.csv" # Set your file name here.

# Lock and load
inotifywait -mrcq $DIR > "$logOfChanges" &
IN_PID=$$

# Do your stuff here
...

# Kill and analyze
kill $IN_PID
cat "$logOfChanges" | while read entry; do
   # Split your CSV, but beware that file names may contain spaces too.
   # Just look up how to parse CSV with bash. :)
   path=... 
   event=...
   ...  # Other stuff like time stamps?
   # Depending on the event…
   case "$event" in
     SOME_EVENT) myHandlingCode path ;;
     ...
     *) myDefaultHandlingCode path ;;
done

或者,在--format上使用-c代替inotifywait会是一个想法。

仅限man inotifywaitman inotifywatch了解更多信息。

答案 3 :(得分:10)

这是一个观察文件夹进行更改并在更新文件时运行less编译器的示例。作为先决条件,您需要npm和模块onchange。节点社区有一大堆不同的监视命令(比如onchange)我不知道任何编译自包含的二进制文件。

npm install less onchange -g

然后你可以使用类似的东西:

onchange "./stylesheets/*.less" -- lessc main.less > main.css

我更喜欢BASH命令而不是Grunt answer我给了一段时间。

答案 4 :(得分:5)

可能是最快的方式..(在1G git repo上,在1秒内返回。)

#!/bin/bash

watch() {

    echo watching folder $1/ every $2 secs.

while [[ true ]]
do
    files=`find $1 -type f -mtime -$2s`
    if [[ $files == "" ]] ; then
        echo "nothing changed"
    else
            echo changed, $files
    fi
    sleep $2
done
}

watch folder 3

答案 5 :(得分:3)

在Mac OS X中,您只需按住Control键单击某个文件夹,然后单击“文件夹操作设置”即可。这将允许您将操作附加到文件夹,即要运行的脚本。

OS X附带了许多预建脚本,或者您可以创建自己的脚本。

答案 6 :(得分:1)

差不多3年后,我推荐这种基于grunt的解决方案。

我在这里创建了一个工作示例https://github.com/reggi/watch-execute

这是Gruntfile.js

module.exports = function (grunt) {
  grunt.initConfig({
    shell: {
      run_file:{
        command: 'sh ./bash.sh',
        options: {
            stdout: true
        }
      }
    },
    watch: {
      run_file: {
        files: ["./watchme/*"],
        tasks: ["shell:run_file"]
      }
    }
  });
  grunt.loadNpmTasks('grunt-contrib-watch');
  grunt.loadNpmTasks('grunt-shell');
};

答案 7 :(得分:1)

我写了一个名为watchfile的通用实用程序来简化这些操作。

它的强度低于inotifywatch,但我更喜欢更简单,更简洁的实用程序。

对于所需的任务,您希望监视当前目录中的任何文件是否已被修改。要在当前目录中递归列出所有文件:

find . -type f

输出每个文件的时间戳信息:

find . -type f -print0 | xargs -0 stat

现在,您可以使用watchfile实用程序监视此输出,并在此信息更改时执行命令CMD

watchfile -s "find . -type f -print0 | xargs -0 stat" -e CMD

答案 8 :(得分:1)

#!/bin/bash

# Author: Devonte
# NGINX WATCH DAEMON
# Place file in root of nginx folder /etc/nginx
# This will test your nginx config on any change and
# if there are no problems it will reload your configuration
# USAGE: sh nginx-watch.sh

dir=`dirname $0`

checksum_initial=`tar -cf - $dir | md5sum | awk '{print $1}'`
checksum_now=$checksum_initial

# Start nginx
nginx

while true
do
    sleep 3
    checksum_now=`tar -cf - $dir | md5sum | awk '{print $1}'`

    if [ $checksum_initial != $checksum_now ]; then
        echo "[ NGINX ] A configuration file changed. Reloading..."
        nginx -t && nginx -s reload;
    fi

    checksum_initial=$checksum_now
done

答案 9 :(得分:0)

为什么不使用AppleScript

http://www.tuaw.com/2009/03/26/applescript-exploring-the-power-of-folder-actions-part-iii/

on adding folder items to this_folder after receiving added_items
tell application "Finder"
...

答案 10 :(得分:0)

如果您只需要检查顶层创建/删除的文件(不检查子文件夹),您可能需要使用以下内容。

它使用的资源很少,因此它可以快速反应,我用它来检查更改的文件。

#!/bin/bash

file="$1"
shift

tmp=$(mktemp)
trap 'rm "$tmp"' EXIT

while true; do
    while [ ! "$tmp" -ot "$file" ]; do
        sleep 0.5
    done
    eval "$@ &"
    echo $! > "$tmp"
    wait
done

答案 11 :(得分:0)

这是一个可以使用的模板,它会每隔120秒检查一次传递目录中的更改,并通知创建目录,文件或名称管道。如果您还希望在删除某些内容时运行命令,请在stackoverflow上查看我的其他答案以获取其他循环示例。

#!/usr/bin/env bash
Var_dir="${1:-/tmp}"
Var_diff_sleep="${2:-120}"
Var_diff_opts="--suppress-common-lines"
Func_parse_diff(){
    _added="$(grep -E '>' <<<"${@}")"
    if [ "${#_added}" != "0" ]; then
        mapfile -t _added_list <<<"${_added//> /}"
        _let _index=0
        until [ "${#_added_list[@]}" = "${_index}" ]; do
            _path_to_check="${Var_dir}/${_added_list[${_index}]}"
            if [ -f "${_path_to_check}" ]; then
                echo "# File: ${_path_to_check}"
            elif [ -d "${_path_to_check}" ]; then
                echo "# Directory: ${_path_to_check}"
            if [ -p "${_path_to_check}" ]; then
                echo "# Pipe: ${_path_to_check}"
            fi
            let _index++
        done
        unset _index
    fi
}
Func_watch_bulk_dir(){
    _current_listing=""
    while [ -d "${Var_dir}" ]; do
        _new_listing="$(ls "${Var_dir}")"
        _diff_listing="$(diff ${Var_dec_diff_opts} <(${Var_echo} "${_current_listing}") <(${Var_echo} "${_new_listing}"))"
        if [ "${_diff_listing}" != "0" ]; then
            Func_parse_diff "${_diff_listing}"
        fi
        _current_listing="${_new_listing}"
        sleep ${Var_diff_sleep}
    done
}

如果您为监控的每种类型的操作替换上面的echoeval <some command>,则会更接近自动化操作。如果您希望在脚本中使用时看到上面的内容,那么请查看我一直致力于通过gpg和tar实现加密和解密自动化的项目的最新script version