web-dev-qa-db-fra.com

Script Bash, dossier surveillé, commande d'exécution

J'essaie de créer un script bash qui prend 2 paramètres: un répertoire et une commande. J'ai besoin de regarder ce répertoire pour les changements et quand quelque chose a été changé, j'ai besoin d'exécuter la commande. Je suis vraiment nouveau dans le domaine des scripts et je ne suis pas vraiment sûr de ce que je fais, alors allez-y doucement. Je suis aussi sur un mac, pas linux. Tous les pointeurs ou ressources externes seraient d'une grande aide. Je sais que beaucoup de gens essaient cela sur Internet et que personne ne semble réussir à le faire. J'essaie vraiment d'imiter la fonctionnalité de la montre 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
35
ThomasReggi

Voici un exemple de surveillance des modifications dans un dossier et d’exécution du compilateur less lorsqu’il est mis à jour. Pour cela, vous avez besoin de npm et le module onchange . La communauté de nœuds a toute une série de commandes de surveillance différentes (comme onchange). À ma connaissance, aucune d'entre elles ne contient de binaires compilés. 

npm install less onchange -g

Ensuite, vous pouvez utiliser quelque chose comme:

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

Je préfère une commande BASH à la réponse Grunt J'ai donné quelques instants en arrière.

10
ThomasReggi

Pour surveiller continuellement de manière récursive le dossier (md5) et exécuter une commande lors d’une modification:

daemon() {
    chsum1=""

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

Fonctionne sur mon OS X car je n’ai pas digest.

Sous Linux, vous pouvez utiliser md5sum pour remplacer la commande md5.

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

Ce script prend deux paramètres [répertoire, commande]. Toutes les 10 secondes, le script exécute check() pour voir si le dossier a été modifié. Sinon, il dort et le cycle se répète.

Dans le cas où le dossier a été modifié, votre commande est evals.

METHODE 2:
Utilisez un cron pour surveiller le dossier.

Vous devrez installer incron:

 Sudo apt-get install incron

Et puis votre script ressemblera à quelque chose comme ça:

#!/bin/bash
eval $1

(Vous n'aurez pas besoin de spécifier le dossier car ce sera le travail du cron de surveiller le répertoire spécifié)

Vous trouverez un exemple complet ici:

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

9
Swift

Je ne peux pas croire que personne n’a encore posté ceci.

Tout d’abord, assurez-vous queinotify-toolssont installés.

Ensuite, utilisez-les comme ceci:

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

Alternativement, utiliser --format au lieu de -c sur inotifywait serait une idée.

Juste man inotifywait et man inotifywatch pour plus d'infos.

8
Evi1M4chine

probablement le moyen le plus rapide de le faire .. (sur repo 1G git, retour sous 1sec.)

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

Sous Mac OS X, vous pouvez simplement cliquer avec le bouton droit de la souris sur un dossier, puis cliquer sur "Configuration des actions sur les dossiers". Cela vous permettra d'attacher des actions à un dossier, c'est-à-dire des scripts à exécuter.

OS X est livré avec un certain nombre de scripts prédéfinis, ou vous pouvez créer les vôtres.

3
John Vargo

Presque 3 ans plus tard, je recommanderais cette solution basée sur le grognement.

J'ai créé un exemple de travail ici https://github.com/reggi/watch-execute .

Voici le 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

J'ai écrit un utilitaire général appelé watchfile pour simplifier ces types d'opérations.

Il est moins puissant que inotifywatch, mais je préfère un utilitaire plus simple et moins détaillé.

Pour la tâche souhaitée, vous souhaitez contrôler si des fichiers du répertoire en cours ont été modifiés. Pour lister tous les fichiers de manière récursive dans le répertoire actuel:

find . -type f

Pour sortir les informations d'horodatage de chacun de ces fichiers:

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

Maintenant, vous pouvez surveiller cette sortie avec l'utilitaire watchfile et exécuter une commande CMD lorsque ces informations changent:

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

Pourquoi ne pas utiliser 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"
...
0
Eric Fortis

Voici un modèle à utiliser, il vérifie toutes les 120 secondes les modifications apportées au répertoire passé et indique la création de répertoires, de fichiers ou de canaux de noms. Si vous souhaitez également exécuter des commandes lorsque quelque chose est supprimé, vérifiez mon autre réponse sur stackoverflow pour des exemples supplémentaires de bouclage.

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

Si vous remplacez les lignes echo ci-dessus par eval <some command> pour chaque type d'action surveillée, vous serez plus près de l'automatisation des actions. Et si vous souhaitez voir à quoi ressemble le texte ci-dessus lorsqu’il est utilisé dans un script, consultez la dernière version de script pour le projet sur lequel j’ai travaillé pour l’automatisation du cryptage et du décryptage via gpg et tar.

0
S0AndS0

Si vous devez uniquement rechercher les fichiers en cours de création/suppression au premier niveau (sans vérifier les sous-dossiers), vous pouvez utiliser les éléments suivants.

Il utilise peu de ressources et peut donc réagir rapidement. Je l'utilise pour vérifier si un fichier a été modifié.

#!/bin/bash

file="$1"
shift

tmp=$(mktemp)
trap 'rm "$tmp"' EXIT

while true; do
    while [ ! "$tmp" -ot "$file" ]; do
        sleep 0.5
    done
    eval "$@ &"
    echo $! > "$tmp"
    wait
done
0
exic