Подтвердить что ты не робот

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
4b9b3361

Ответ 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');
};

Ответ 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.