我正在尝试创建一个带有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
答案 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监视指定目录的工作)
可在此处找到完整的工作示例:
答案 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 inotifywait
和man 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
}
如果您为监控的每种类型的操作替换上面的echo
行eval <some command>
,则会更接近自动化操作。如果您希望在脚本中使用时看到上面的内容,那么请查看我一直致力于通过gpg和tar实现加密和解密自动化的项目的最新script version。