特定のファイルまたはディレクトリが変更されたときにシェルスクリプトを実行したい。
どうすれば簡単にできますか?
inotify-tools を使用します。
このスクリプトを使用して、ディレクトリツリーの変更に対してビルドスクリプトを実行します。
#!/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
manページ を確認してください。
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
前述したように、inotify-toolsはおそらく最良のアイデアです。ただし、楽しみのためにプログラミングしている場合は、 tail -f を適切に適用することで、ハッカーXPを獲得できます。
このスクリプトはどうですか? '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
別のオプションを次に示します。 http://fileschanged.sourceforge.net/
特に「ディレクトリを監視し、新規または変更されたファイルをアーカイブする」「例4」を参照してください。
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
デバッグのためだけに、シェルスクリプトを記述し、保存時に実行する場合、これを使用します。
#!/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
編集:Ubuntu 12.04でテスト済み、Mac OSの場合、ls行を次のように変更します。
"$(ls -lT $file | awk '{ print $8 }')"
以下を〜/ .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
:の使用例
関連ファイルを変更するたびにRails test
を実行したいとします。
1。監視したい関連ファイルのリストを作成します:
手動で行うこともできますが、ack
はそのリストを作成するのに非常に役立ちます。
ack --type-add=Rails:ext:rb,erb --Rails -f > Inotifyfile
2。 inotifywait
にジョブを実行するよう依頼します
while inotifywait --fromfile Inotifyfile; do Rails test; done
それでおしまい!
注:Vagrantを使用してVMでコードを実行する場合、 mhallin/vagrant-notify-forwarder 拡張機能が役立つ場合があります。
UPDATE:さらに良いのは、alias
を作成してファイルを削除することです:
alias rtest="while inotifywait $(ack --type-add=Rails:ext:rb,erb --Rails -f | tr \\n \ ); do Rails test; done"