2010-11-04 5 views
0

J'ai écrit ce script pour trouver tous les fichiers/répertoires auxquels $ WWWUSER a des permissions d'écriture. Au début, j'ai stocké les éléments correspondants restants dans un fichier temporaire. Je nouveau il doit y avoir un moyen sans utiliser de fichiers, c'est donc ma "solution". Cela fonctionne, mais c'est plutôt lent. Des conseils?Comment optimiser un script bash? (Trouver des fichiers, ignorer ceux sur la liste blanche, rapporter le reste)

Mise à jour: Sur une structure de répertoires contenant environ 7k répertoires et fichiers (30K ~ 8k) whitelistings le script prend environ 15 minutes ... (système de fichiers ext3, UW320 disque SCSI).

#!/usr/bin/env bash 
# Checks the webroot for files owned by www daemon and 
# writable at the same time. This is only needed by some files 
# So we'll check with a whitelist 

WWWROOT=/var/www 
WWWUSER=www-data 
WHITELIST=(/wp-content/uploads 
/wp-content/cache 
/sitemap.xml 
) 
OLDIFS=$IFS 
IFS=$'\n' 

LIST=($(find $WWWROOT -perm /u+w -user $WWWUSER -o -perm /g+w -group $WWWUSER)) 
IFS=$OLDIFS 

arraycount=-1 
whitelist_matches=0 

for matchedentry in "${LIST[@]}"; do 
     arraycount=$(($arraycount+1)) 

     for whitelistedentry in "${WHITELIST[@]}"; do 
       if [ $(echo $matchedentry | grep -c "$whitelistedentry") -gt 0 ]; then 
         unset LIST[$arraycount] 
         whitelist_matches=$(($whitelist_matches+1)) 
       fi 
     done 
LISTCOUNT=${#LIST[@]} 
done 

if [ $(echo $LISTCOUNT) -gt 0 ]; then 
     for item in "${LIST[@]}"; do 
       echo -e "$item\r" 
     done 
     echo "$LISTCOUNT items are writable by '$WWWUSER' ($whitelist_matches whitelisted)." 
else 
     echo "No writable items found ($whitelist_matches whitelisted)." 
fi 
+0

Est-il possible d'utiliser une application externe pour exécuter ceci, par ex. Perl? Il pourrait être raccourci et accélérer un peu en utilisant un hachage pour les références de la liste blanche. En utilisant un Shebang différent, il pourrait être le même. – 0xCAFEBABE

+0

C'est possible oui, mais pas désiré. Mais je vais vérifier l'idée de TME, puis rechercher comment implémenter le vôtre. Merci! – weeheavy

Répondre

1

(je n'ai pas une configuration pratique pour tester cela sur, mais il devrait travail ...)

#!/usr/bin/env bash 
# Checks the webroot for files owned by www daemon and 
# writable at the same time. This is only needed by some files 
# So we'll check with a whitelist 

WWWROOT=/var/www 
WWWUSER=www-data 
WHITELIST="(/wp-content/uploads|/wp-content/cache|/sitemap.xml)" 

listcount=0 
whitelist_matches=0 

while IFS="" read -r matchedentry; do 
    if [[ "$matchedentry" =~ $WHITELIST ]]; then 
     ((whitelist_matches++)) 
    else 
     echo -e "$matchedentry\r" 
     ((listcount++)) 
    fi 
done < <(find "$WWWROOT" -perm /u+w -user $WWWUSER -o -perm /g+w -group $WWWUSER) 

if (($listcount > 0)); then 
        echo "$listcount items are writable by '$WWWUSER' ($whitelist_matches whitelisted)." 
else 
        echo "No writable items found ($whitelist_matches whitelisted)." 
fi 

Edit: J'ai intégré les suggestions de Dennis Williamson sur les mathématiques; aussi, voici un moyen de construire le modèle de WHITELIST à partir d'un tableau:

WHITELIST_ARRAY=(/wp-content/uploads 
/wp-content/cache 
/sitemap.xml 
) 

WHITELIST="" 
for entry in "${WHITELIST_ARRAY[@]}"; do 
    WHITELIST+="|$entry" 
done 
WHITELIST="(${WHITELIST#|})" # this removes the stray "|" from the front, and adds parens 

Edit2: Commentaire de Sorpigal à éliminer de nouveaux processus m'a fait penser - je soupçonne que la plupart des speedup dans cette version vient de ne pas en cours d'exécution ~ 40 invocations de grep par fichier scanné, et juste un peu de supprimer la manipulation de la matrice, mais il m'est venu à l'esprit que si vous n'avez pas besoin des totaux à la fin, vous pouvez supprimer la boucle while principale et le remplacer par:

find "$WWWROOT" -perm /u+w -user $WWWUSER -o -perm /g+w -group $WWWUSER | grep -v "$WHITELIST" 

... , mais une seule fois (et exécute la liste complète des fichiers via t hat one single instance), et une fois commencé grep sera capable de balayer la liste des fichiers plus rapidement qu'une boucle bash ...

+0

Hah, tu as posté du code presque identique au mien pendant que je composais. +1 et le mien supprimé. La prochaine fois, je me souviendrai de ne pas tomber sur des tuyaux sous-marins. – Sorpigal

+1

En outre, je pense qu'il est important de noter ici que l'optimisation de ce processus consiste à éliminer autant de sous-couches et d'execs que possible. – Sorpigal

+0

Ceci est friggin génial, jusqu'à 4 secondes d'exécution! Merci beaucoup * tout le monde *! – weeheavy

1

Il existe une autre possibilité. En changeant la liste blanche en un modèle regex vous pouvez utiliser l'opérateur = ~ bash regex (version 3 et plus) pour faire correspondre rapidement n'importe quel mot trouvé avec la liste: if ($ word = ~ $ pattern) $ pattern peut être "^ (whitelistentry1 | whitelistentry2 | whitelistentry3 | ...) $ ".

+0

Je ne savais pas que c'était possible avec bash, je vais y jeter un coup d'œil. Je vous remercie. – weeheavy

Questions connexes