it-swarm.com.de

Bash-Skript, Ordner beobachten, Befehl ausführen

Ich versuche, ein Bash-Skript zu erstellen, das zwei Parameter benötigt: ein Verzeichnis und einen Befehl. Ich muss dieses Verzeichnis auf Änderungen überprüfen und wenn etwas geändert wurde, muss ich den Befehl ausführen. Ich bin wirklich kein Neuling im Bash-Scripting und bin mir nicht wirklich sicher, was ich mache. Ich bin auch auf einem Mac, nicht auf Linux. Jegliche Hinweise oder externe Ressourcen würden sehr hilfreich sein. Ich weiß, dass viele Leute dies im Internet ausprobieren und es scheint, dass niemand es richtig versteht. Ich versuche wirklich, die Uhrenfunktionalität von SASS nachzuahmen. 

#!/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
35
ThomasReggi

Hier ist ein Beispiel für das Überwachen eines Ordners auf Änderungen und das Ausführen eines Compiler mit weniger, wenn einer aktualisiert wird. Als Voraussetzung benötigen Sie npm und dazu das Modul onchange . Die Knotengemeinschaft verfügt über eine ganze Reihe verschiedener Watch-Befehle (z. B. onchange). Ich kenne keine binären binären kompilierten Binaries. 

npm install less onchange -g

Dann kannst du so etwas verwenden:

onchange "./stylesheets/*.less" -- lessc main.less > main.css

Ich bevorzuge einen BASH-Befehl gegenüber der Grunt-Antwort Ich gab eine Weile zurück.

10
ThomasReggi

Um fortlaufend den Ordner (md5) rekursiv zu überwachen und bei Änderung einen Befehl auszuführen:

daemon() {
    chsum1=""

    while [[ true ]]
    do
        chsum2=`find src/ -type f -exec md5 {} \;`
        if [[ $chsum1 != $chsum2 ]] ; then           
            compile
            chsum1=$chsum2
        fi
        sleep 2
    done
}

Funktioniert auf meinem OS X, da ich digest nicht habe.

Unter Linux können Sie md5sum als Ersatz für den md5-Befehl verwenden.

36
Radek

METHODE 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 $*

Dieses Skript enthält zwei Parameter [Verzeichnis, Befehl]. Alle 10 Sekunden führt das Skript check() aus, um zu sehen, dass sich der Ordner geändert hat. Wenn nicht, schläft es und der Zyklus wiederholt sich.

Für den Fall, dass sich der Ordner geändert hat, evals ist Ihr Befehl.

METHODE 2:
Verwende einen Cron, um den Ordner zu überwachen.

Sie müssen inkron installieren:

 Sudo apt-get install incron

Und dann sieht dein Skript so aus:

#!/bin/bash
eval $1

(Sie müssen den Ordner nicht angeben, da der cron die Aufgabe hat, das angegebene Verzeichnis zu überwachen.)

Ein ausführliches Arbeitsbeispiel finden Sie hier:

http://www.errr-online.com/index.php/2011/02/25/monitor-a-directory-or-file-for-changes-on-linux-using-inotify/

9
Swift

Ich kann nicht glauben, dass noch niemand dies gepostet hat.

Stellen Sie zunächst sicher, dassinotify-toolsinstalliert ist.

Dann verwenden Sie sie wie folgt:

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

Alternativ wäre die Verwendung von --format anstelle von -c für inotifywait eine Idee.

Nur man inotifywait und man inotifywatch für weitere Infos.

8
Evi1M4chine

wahrscheinlich der schnellste Weg, es zu tun .. (auf 1G Git Repo, kehrt unter 1 Sekunde zurück.)

#!/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
5
Devrim

In Mac OS X können Sie einfach mit der rechten Maustaste auf einen Ordner klicken und dann auf "Ordneraktionen einrichten" klicken. Dadurch können Sie Aktionen an einen Ordner anhängen, d. H. Skripts, die ausgeführt werden sollen.

OS X wird mit einer Reihe von vorgefertigten Skripts geliefert, oder Sie können eigene erstellen.

3
John Vargo

Fast 3 Jahre später würde ich diese grunzbasierte Lösung empfehlen.

Ich habe hier ein Funktionsbeispiel erstellt https://github.com/reggi/watch-execute .

Hier ist der 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');
};
1
ThomasReggi

Ich habe ein allgemeines Dienstprogramm namens watchfile geschrieben, um solche Operationen zu vereinfachen.

Es ist weniger leistungsfähig als inotifywatch, aber ich bevorzuge eine einfachere, weniger ausführliche Anwendung.

Für die gewünschte Aufgabe möchten Sie überwachen, ob Dateien im aktuellen Verzeichnis geändert wurden. Um alle Dateien im aktuellen Verzeichnis rekursiv aufzulisten:

find . -type f

So geben Sie die Zeitstempelinformationen für jede dieser Dateien aus:

find . -type f -print0 | xargs -0 stat

Jetzt können Sie diese Ausgabe mit dem Dienstprogramm watchfile überwachen und einen Befehl CMD ausführen, wenn sich diese Informationen ändern:

watchfile -s "find . -type f -print0 | xargs -0 stat" -e CMD
1
swalog
#!/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
1
Devonte

Warum nicht AppleScript verwenden?

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"
...
0
Eric Fortis

Hier ist eine Vorlage, mit der Sie arbeiten können. Sie wird alle 120 Sekunden auf Änderungen im übergebenen Verzeichnis überprüft und bei der Erstellung von Verzeichnissen, Dateien oder Namens-Pipes benachrichtigt. Wenn Sie auch Befehle ausführen möchten, wenn etwas entfernt wird, überprüfen Sie meine andere Antwort in stackoverflow auf weitere Schleifenbeispiele.

#!/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
}

Wenn Sie die echo-Zeilen oben für jeden überwachten Aktionstyp durch eval <some command> ersetzen, werden Sie der Automatisierung von Aktionen immer näher kommen. Wenn Sie wissen möchten, wie das obige Skript aussieht, wenn Sie es in einem Skript verwenden, dann schauen Sie sich die neueste script-Version für das Projekt an, an dem ich zur Automatisierung der Verschlüsselung und Entschlüsselung über gpg und tar gearbeitet habe.

0
S0AndS0

Wenn Sie nur prüfen müssen, ob Dateien auf oberster Ebene erstellt/gelöscht werden (und keine Unterordner prüfen), möchten Sie möglicherweise Folgendes verwenden.

Es benötigt nur wenige Ressourcen, daher kann es schnell reagieren. Ich verwende es, um nach einer geänderten Datei zu suchen.

#!/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
0
exic