Bash script, посмотреть папку, выполнить команду
Я пытаюсь создать bash script, который принимает 2 параметра: каталог и команду. Мне нужно посмотреть этот каталог для изменений, и когда что-то изменилось, мне нужно выполнить команду. Я действительно новичок в написании сценариев 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
Ответы
Ответ 1
Здесь приведен пример просмотра папки для изменений и запуска менее компилятора при обновлении. В качестве prereq вам нужно npm
, и они будут onchange. Сообщество node имеет целую кучу различных команд часов (например, onchange). Я не знаю ни одного из них, которые являются скомпилированными автономными двоичными файлами.
npm install less onchange -g
Затем вы можете использовать что-то вроде:
onchange "./stylesheets/*.less" -- lessc main.less > main.css
Я предпочитаю команду BASH над ответом Grunt, который я дал некоторое время назад.
Ответ 2
Чтобы постоянно рекурсивно отслеживать папку (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
.
Ответ 3
МЕТОД 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 $*
Этот script принимает два параметра [каталог, команда]. Каждые 10 секунд script выполняет check()
, чтобы увидеть, что папка изменилась. Если он не спит, и цикл повторяется.
В случае изменения папки, eval
ваша команда.
МЕТОД 2:
Используйте cron для просмотра папки.
Вам нужно будет установить incron:
sudo apt-get install incron
И тогда вы script будете выглядеть примерно так:
#!/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/
Ответ 4
Я не могу поверить, что никто еще не опубликовал это.
Сначала убедитесь, что установлены 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
для получения дополнительной информации.
Ответ 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
Ответ 6
В Mac OS X вы можете просто щелкнуть правой кнопкой мыши папку, а затем нажать "Настройка действий с папками". Это позволит вам приложить действия к папке, то есть сценарии для запуска.
OS X поставляется с несколькими готовыми сценариями, или вы можете создать свой собственный.
Ответ 7
Почти 3 года спустя, и я бы рекомендовал это решение, основанное на хрюке.
Я создал рабочий пример здесь 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');
};
Ответ 8
Почему бы не использовать 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"
...
Ответ 9
Если вам нужно проверить файлы, которые создаются/удаляются на верхнем уровне (не проверяя вложенные папки), вы можете использовать следующее.
Он использует несколько ресурсов, поэтому он может быстро реагировать, я использую его для проверки измененного файла.
#!/bin/bash
file="$1"
shift
tmp=$(mktemp)
trap 'rm "$tmp"' EXIT
while true; do
while [ ! "$tmp" -ot "$file" ]; do
sleep 0.5
done
eval "[email protected] &"
echo $! > "$tmp"
wait
done
Ответ 10
Я написал общую утилиту 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
Ответ 11
#!/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
Ответ 12
Здесь шаблон, с которым нужно работать, проверяет каждые 120 секунд изменения в переданном каталоге и уведомляет о создании каталогов, файлов или имен. Если вы также хотите запускать команды, когда что-то удалено, проверьте другой ответ на fooobar.com/info/168639/... для дополнительных примеров циклов.
#!/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>
для каждого контролируемого вами типа действий, вы будете ближе к автоматизации действий. И если вы хотите увидеть, как выглядит выше, когда используется в script, то посмотрите на проект script для проекта Я работал над автоматизацией шифрования и дешифрования через gpg и tar.