我正在尝试创建一个带有 2 个参数的 bash 脚本:
我想观察目录参数的更改:当某些内容发生更改时,脚本应该执行该命令。
我运行的是 MacOS,而不是 Linux;任何指针或外部资源都会有很大帮助,因为我发现这很难实现。真的,OI 正在尝试模仿 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
连续递归监视文件夹 (md5) 并在更改时执行命令:
daemon() {
chsum1=""
while [[ true ]]
do
chsum2=`find src/ -type f -exec md5 {} \;`
if [[ $chsum1 != $chsum2 ]] ; then
if [ -n "$chsum1" ]; then
compile
fi
chsum1=$chsum2
fi
sleep 2
done
}
适用于我的 OS X,因为我没有
digest
。
在 Linux 上,您可以使用
md5sum
代替 md5
命令。
我不敢相信还没有人发布这个。
首先确保
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
了解更多信息。
方法一:
#!/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 $*
该脚本接受两个参数[目录、命令]。脚本每 10 秒执行一次
check()
以查看文件夹是否已更改。如果没有,它就会休眠并重复循环。如果文件夹已更改,则
eval
是您的命令。
方法2:
使用 cron 来监视文件夹。
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/
#!/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
OS X 附带了许多预构建的脚本,或者您也可以创建自己的脚本。
我在这里创建了一个工作示例
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');
};
inotifywatch
强大,但我更喜欢一个更简单、更简洁的实用程序。对于所需的任务,您想要监视当前目录中的任何文件是否已被修改。递归列出当前目录中的所有文件:
find . -type f
输出每个文件的时间戳信息:
find . -type f -print0 | xargs -0 stat
现在,您可以使用
watchfile
实用程序监视此输出,并在该信息发生变化时执行命令
CMD
:
watchfile -s "find . -type f -print0 | xargs -0 stat" -e CMD
#!/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
它使用很少的资源,因此它可以快速反应,我用它来检查更改的文件。
#!/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
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 进行加密和解密自动化的项目的最新脚本版本。
Radek 的答案“有点”对我有用(OSx),但它减慢了我的终端速度。我对其进行了一些修改,以下是我认为对我有用的内容:
#!/bin/bash
daemon() {
chsum1=""
targetFolder=path-to-target-folder
while [[ true ]]
do
chsum2=`find ${targetFolder} -type f | xargs stat -f "%m" | md5`
if [[ $chsum1 != $chsum2 ]] ; then
# echo the date to indicate we are updating
date
./do-something.sh
# tracks the check-sum
chsum1=$chsum2
fi
# sleep for 2 secs
sleep 2
done
}
daemon
肉在:
chsum2=`find ${targetFolder} -type f | xargs stat -f "%m" | md5`
这意味着find all files in ${targetFolder}, pipe that into stat -f "%m" 1-by-1 and then pipe that into md5
。
stat -f "%m" [filepath]
为您提供最后修改的时间戳。帮助我改进它。谢谢!
find src -name "*" | xargs stat -f "%Sa %N" | sort
示例:
PREVIOUS_STATE=""
while true; do
CURRENT_STATE=`find src -name "*" | xargs stat -f "%Sa %N" | sort`
if [[ $CURRENT_STATE != $PREVIOUS_STATE ]]; then
# do something here
PREVIOUS_STATE=$CURRENT_STATE
fi
sleep 0.2
done