我想在特定文件或目录更改时运行Shell脚本。
我如何轻松做到这一点?
我想在特定文件或目录更改时运行Shell脚本。
我如何轻松做到这一点?
Answers:
链接的Github页面上有许多示例。这是其中之一。
#!/bin/sh
cwd=$(pwd)
inotifywait -mr \
--timefmt '%d/%m/%y %H:%M' --format '%T %w %f' \
-e close_write /tmp/test |
while read -r date time dir file; do
changed_abs=${dir}${file}
changed_rel=${changed_abs#"$cwd"/}
rsync --progress --relative -vrae 'ssh -p 22' "$changed_rel" \
usernam@example.com:/backup/root/dir && \
echo "At ${time} on ${date}, file $changed_abs was backed up via rsync" >&2
done
您可以尝试entr
在文件更改时运行任意命令的工具。文件示例:
$ ls -d * | entr sh -c 'make && make test'
要么:
$ ls *.css *.html | entr reload-browser Firefox
或Changed!
在file.txt
保存文件时打印:
$ echo file.txt | entr echo Changed!
对于目录,请使用-d
,但您必须在循环中使用它,例如:
while true; do find path/ | entr -d echo Changed; done
要么:
while true; do ls path/* | entr -pd echo Changed; done
entr
是最简单,最易组合且适用于UNIX的工具。爱它。incron
可以替换为,甚至可以使用entr
流程管理器。runit
s6
systemd
entr
用来监视该日志文件和touch
日志时,一切正常,但是当脚本追加到该文件时,将entr
失败。这可能是因为我在fstab中为我的ssd设置了noatime-但这仅停止更新访问时间而不是修改时间,因此这使我感到困惑。然后,我尝试entr -cdr
使用日志更新的文件目录。识别与目录内容更改,但是-r
不起作用。该entr
过程刚刚结束。
我使用此脚本在目录树中的更改上运行构建脚本:
#!/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
用途inotify-tools
。查看inotifywait
手册页,了解如何自定义触发构建的内容。
这个脚本怎么样?使用“ 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
inotifywait
(inotify-tools),因为它在文件更新时几乎立即唤醒。(您的脚本可能需要等待最多5秒钟才能被注意到。)您的脚本还必须每5秒钟唤醒一次,生成一个进程,检查结果,然后再进入睡眠状态,而这足以“在5秒钟内将其一起入侵分钟”脚本,浪费CPU资源,应在生产代码中避免使用。
enter
但是有时候我需要在无法安装任何工具的系统上做一些事情,因此在任何系统上都可以使用的方法(好吧,我没有遇到任何问题stat
都是非常有用的。我m使用这种不带循环的方法比较两次(文件夹时间戳和文件)以查看是否需要重新生成文件,然后从cron运行检查
这是另一个选项:http : //fileschanged.sourceforge.net/
尤其请参见“示例4”,该示例“监视目录并存档任何新文件或更改的文件”。
仅出于调试目的,当我编写Shell脚本并希望其在保存时运行时,我使用以下命令:
#!/bin/bash
file="$1" # Name of file
command="${*:2}" # Command to run on change (takes rest of line)
t1="$(ls --full-time $file | awk '{ print $7 }')" # Get latest save time
while true
do
t2="$(ls --full-time $file | awk '{ print $7 }')" # Compare to new save time
if [ "$t1" != "$t2" ];then t1="$t2"; $command; fi # If different, run command
sleep 0.5
done
运行为
run_on_save.sh myfile.sh ./myfile.sh arg1 arg2 arg3
编辑:在Mac OS的Ubuntu 12.04上进行了上述测试,将ls行更改为:
"$(ls -lT $file | awk '{ print $8 }')"
watch
命令可以对此进行改进,但是我喜欢这种实现。感谢分享。
将以下内容添加到〜/ .bashrc中:
function react() {
if [ -z "$1" -o -z "$2" ]; then
echo "Usage: react <[./]file-to-watch> <[./]action> <to> <take>"
elif ! [ -r "$1" ]; then
echo "Can't react to $1, permission denied"
else
TARGET="$1"; shift
ACTION="$@"
while sleep 1; do
ATIME=$(stat -c %Z "$TARGET")
if [[ "$ATIME" != "${LTIME:-}" ]]; then
LTIME=$ATIME
$ACTION
fi
done
fi
}
inotifywait
可以满足你。
这是一个常见的示例:
inotifywait -m /path -e create -e moved_to -e close_write | # -m is --monitor, -e is --event
while read path action file; do
if [[ "$file" =~ .*rst$ ]]; then # if suffix is '.rst'
echo ${path}${file} ': '${action} # execute your command
echo 'make html'
make html
fi
done
flag=$(echo file_content)
。if [ flag == 'stop' ] then exit 1
假设您希望rake test
每次在app /和test /目录中修改任何ruby文件(“ * .rb”)时都运行。
只需获取监视文件的最新修改时间,然后每秒检查一次是否已更改。
脚本代码
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
好处
警告
-printf
选项在Ubuntu上很好用,但在MacOS上不起作用。