Shell-script (besoin d'aide)
Fermé
momsse
-
8 mai 2007 à 16:58
asevere Messages postés 13084 Date d'inscription lundi 28 janvier 2002 Statut Webmaster Dernière intervention 3 février 2022 - 9 mai 2007 à 21:49
asevere Messages postés 13084 Date d'inscription lundi 28 janvier 2002 Statut Webmaster Dernière intervention 3 février 2022 - 9 mai 2007 à 21:49
A voir également:
- Shell-script (besoin d'aide)
- Script vidéo youtube - Guide
- Classic shell windows 11 - Télécharger - Personnalisation
- Ghost script - Télécharger - Polices de caractères
- Script bat - Guide
- Microsoft activation script - Accueil - Windows
15 réponses
jipicy
Messages postés
40842
Date d'inscription
jeudi 28 août 2003
Statut
Modérateur
Dernière intervention
10 août 2020
4 897
8 mai 2007 à 20:13
8 mai 2007 à 20:13
Salut Adrien,
Je ne dirai que 3 mots : chapeau bas Mister ;-))
Je ne dirai que 3 mots : chapeau bas Mister ;-))
Écrire un script-shell nettoyer.sh qui supprime à partir du répertoire courant tous les fichiers dont le nom se termine
par un caractère ’∼’ (même si le nom du fichier commence par un caractère ’.’) ou dont le nom débute et se ter-
mine par un caractère ’#’ ; ces fichiers sont fréquemment des fichiers temporaires. La suppression de ces fichiers
devra s’effectuer récursivement dans toute la sous-arborescence du répertoire courant et devra fonctionner même
à l’intérieur des sous-répertoire dont le nom commence par un caractère ’.’. Outre l’ensemble des commandes
internes au shell bash, les seules commandes externes utilisables sont dirname, basename et bien entendu rm.
Votre script-shell NE DEVRA PAS utiliser les commandes ls, find, grep ou egrep.
par un caractère ’∼’ (même si le nom du fichier commence par un caractère ’.’) ou dont le nom débute et se ter-
mine par un caractère ’#’ ; ces fichiers sont fréquemment des fichiers temporaires. La suppression de ces fichiers
devra s’effectuer récursivement dans toute la sous-arborescence du répertoire courant et devra fonctionner même
à l’intérieur des sous-répertoire dont le nom commence par un caractère ’.’. Outre l’ensemble des commandes
internes au shell bash, les seules commandes externes utilisables sont dirname, basename et bien entendu rm.
Votre script-shell NE DEVRA PAS utiliser les commandes ls, find, grep ou egrep.
fiddy
Messages postés
11069
Date d'inscription
samedi 5 mai 2007
Statut
Contributeur
Dernière intervention
23 avril 2022
1 841
8 mai 2007 à 17:19
8 mai 2007 à 17:19
Es-tu sûr que c'est possible juste avec dirname, basename et rm ???
Vous n’avez pas trouvé la réponse que vous recherchez ?
Posez votre question
J'aimerais pouvoir les filtrer avec un
echo */[.#]*[~#]
Mais ce ne fonctionne pas ... une idée ?
echo */[.#]*[~#]
Mais ce ne fonctionne pas ... une idée ?
asevere
Messages postés
13084
Date d'inscription
lundi 28 janvier 2002
Statut
Webmaster
Dernière intervention
3 février 2022
426
8 mai 2007 à 19:56
8 mai 2007 à 19:56
Bonoir,
Je repasserai plus tard si tu veux des détails, mais tout est dans le manuel de bash, (les deux commandes shopt sont particuliérement importante ici)
@+
#!/bin/sh function search_dir() { DIR=$1; for element in $DIR/* ; do if [ -e $element -a -d $element -a $(basename $element) != ".." -a $(basename $element) != "." ]; then for file in $element/*~; do if [ -f $file ]; then echo "Removing $file" rm -f $file; fi; done search_dir "$element"; fi; done; } shopt -s dotglob shopt -s nullglob search_dir ".";Voila une fonction recursive n'utilisant que des command internes au bash, ça doit faire ce qu'il faut, il doit exister plus simple, mais la ça me semble assez compréhensible donc je laisse tel que.
Je repasserai plus tard si tu veux des détails, mais tout est dans le manuel de bash, (les deux commandes shopt sont particuliérement importante ici)
@+
asevere
Messages postés
13084
Date d'inscription
lundi 28 janvier 2002
Statut
Webmaster
Dernière intervention
3 février 2022
426
8 mai 2007 à 19:58
8 mai 2007 à 19:58
Pour tester, il faut meiux remplacer la commande rm -f par rm -i (la question sera posée à chaque suppression)
Cordialement
Cordialement
Je te remercie asevere, super sympa !
Par contre il y a trop de fonction que l'on a pas vu en cours, ton script est d'un assez haut niveau (pour nous), on aurai jamais pu nous demander de pondre quelques chose comme ca...
Sa serai sympa si tu pourrai me la decortiquer (un tout petit peu), juste deux ou trois commentaire sur les phases importante, que je puisse comprendre le mécanisme ...
Il y a pas quelque chose de plus simple avec dirname, basename et rm ?
Je pensais que l'on pouvais par exemple afficher les fichiers que l'on souhaitait avec quelque chose qui ressemblerait a :
echo */[#]*[#] .*[~] *[~]
puis les supprimer avec un for:
for elu in $(echo */[#]*[#] .*[~] *[~]);
do
rm $elu
done
Bien sûr j'ecris tous ca, mais j'ai pas réussi à mettre ca en forme ....
Si on pourrait me guider sur cette piste ca serait cool !
Merci encore pour le boulot !!
Par contre il y a trop de fonction que l'on a pas vu en cours, ton script est d'un assez haut niveau (pour nous), on aurai jamais pu nous demander de pondre quelques chose comme ca...
Sa serai sympa si tu pourrai me la decortiquer (un tout petit peu), juste deux ou trois commentaire sur les phases importante, que je puisse comprendre le mécanisme ...
Il y a pas quelque chose de plus simple avec dirname, basename et rm ?
Je pensais que l'on pouvais par exemple afficher les fichiers que l'on souhaitait avec quelque chose qui ressemblerait a :
echo */[#]*[#] .*[~] *[~]
puis les supprimer avec un for:
for elu in $(echo */[#]*[#] .*[~] *[~]);
do
rm $elu
done
Bien sûr j'ecris tous ca, mais j'ai pas réussi à mettre ca en forme ....
Si on pourrait me guider sur cette piste ca serait cool !
Merci encore pour le boulot !!
Pas d'idée ?
jipicy
Messages postés
40842
Date d'inscription
jeudi 28 août 2003
Statut
Modérateur
Dernière intervention
10 août 2020
4 897
9 mai 2007 à 08:27
9 mai 2007 à 08:27
Ben non ;-((
Il est vrai que sans "ls", "find" et "grep", la tâche s'annonce ardue !
Par contre, si aucune solution ne t'est fournie d'ici là, pourras-tu par la suite poster le corrigé de cet exercice ?
Merci d'avance ;-))
Il est vrai que sans "ls", "find" et "grep", la tâche s'annonce ardue !
Par contre, si aucune solution ne t'est fournie d'ici là, pourras-tu par la suite poster le corrigé de cet exercice ?
Merci d'avance ;-))
Salut jipicy,
Oui c'est vrai que c'est du haut niveau, j'espère trouver un corrigé avant les exam, sinon ca serait un peu bête ...
Autrement en relisant le script de asevere, j'ai l'impression qu'il ne supprime que les fichier se términant par ~, hors on nous demandait aussi de supprimer:
-ceux finissant et commançant par #: ex: (#fichier#)
-ceux commancant par un point et finissant par ~ : ex:( .fichier~)
-Et ceux qu'il a traité, finissant par un ~: ex(fichier~)
Autrement, n'y a t-il pas un moyen d'épuré un peu ce code en essayant de se passer de shopt ! D'ailleurs j'ai aucune page de manuel sur cette fonction ...
Autrement pourrait tu me decortiquer son if (je ne connais pas les test -a ) ...
Merci d'avance !
Oui c'est vrai que c'est du haut niveau, j'espère trouver un corrigé avant les exam, sinon ca serait un peu bête ...
Autrement en relisant le script de asevere, j'ai l'impression qu'il ne supprime que les fichier se términant par ~, hors on nous demandait aussi de supprimer:
-ceux finissant et commançant par #: ex: (#fichier#)
-ceux commancant par un point et finissant par ~ : ex:( .fichier~)
-Et ceux qu'il a traité, finissant par un ~: ex(fichier~)
Autrement, n'y a t-il pas un moyen d'épuré un peu ce code en essayant de se passer de shopt ! D'ailleurs j'ai aucune page de manuel sur cette fonction ...
Autrement pourrait tu me decortiquer son if (je ne connais pas les test -a ) ...
Merci d'avance !
D'ailleurs je viens de voir aussi que ca fonction prend un argument, hors il ne faut pas, non plus ...
jipicy
Messages postés
40842
Date d'inscription
jeudi 28 août 2003
Statut
Modérateur
Dernière intervention
10 août 2020
4 897
9 mai 2007 à 09:12
9 mai 2007 à 09:12
Re-
Pour "shopt", voir le "man bash" et rchercher l'option "shopt" :
Pour "shopt", voir le "man bash" et rchercher l'option "shopt" :
shopt [-pqsu] [-o] [nom_opt ...] Bascule la valeur des variables contrôlant le comportement optionnel du shell. Sans option, ou avec l'option -p, une liste de toutes les options configurables est affichée, avec l'indica- tion de l'état de chacune d'entre elles. L'option -p réclame un affichage susceptible d'être réutilisé en entrée. Les autres options ont les significations suivantes : -s Activer chaque nom_opt indiqué. -u Désactiver chaque nom_opt indiqué. -q Supprimer la sortie normale (mode silencieux). Le code de retour indique si l'option nom_opt est active ou non. Si plusieurs nom_opt sont fournis en argument de l'option -q, le code de retour est nul si tous les nom_opt sont actifs, et non-nul sinon. -o Restreindre les valeurs des nom_opts à celles définies pour l'option -o de la commande set interne. Si l'option -s ou -u est utilisé sans argument nom_opt, l'affichage est limité aux options qui sont actives ou inac- tives, respectivement. sauf indication contraire, les options shopt sont désactivés par défaut. Le code de retour lors d'un affichage est zéro si tous les nom_opt sont actifs, non-nul sinon. Lors d'une activation ou inhibition, le code de retour est nul sauf si nom_opt n'est pas une option valide du shell. La liste des options shopt est : dotglob Si cette option est active, bash inclut les noms de fichiers commençant par un `.' dans les résultats des développements de noms de fichiers. nullglob Si cette option est active, bash autorise les motifs ne correspondant à aucun fichiers (voir Développement des noms de fichiers plus haut) à se développer en une chaîne nulle plutôt qu'en une valeur littérale.idem pour "test" ([...]) et non pas "if", voir le man bash :
test expr [ expr ] Renvoie la valeur 0 (vrai) ou 1 (faux) en fonction de l'évalua- tion de l'expression conditionnelle expr. Chaque opérateur et opérande doit être représenté par un argument distinct. Les expressions sont composées des unités élémentaires décrites plus haut dans EXPRESSIONS CONDITIONNELLES Les expressions peuvent être combinées avec les opérateurs suiv- ant, par ordre de précédence décroissante : ! expr Vrai si expr est fausse ( expr ) Renvoie la valeur de expr. Peut servir à surcharger la précédence normale des opérateurs. expr1 -a expr2 Vrai si expr1 et expr2 sont toutes deux vraies. expr1 -o expr2 Vrai si expr1 ou expr2 est vraie.;-))
Merci jipicy,
Pense tu que l'on peut se passer de la fonction shopt ?
Autrement, sa fonction prend en argument le nom d'un répertoire, alors que la fonction ne doit en prendre aucun, et se lancé à partir du répertoire courant et de ces sou repertoires...
Aussi peut t-on remplacer -a par && et -o par || ?
Merci encore !
Pense tu que l'on peut se passer de la fonction shopt ?
Autrement, sa fonction prend en argument le nom d'un répertoire, alors que la fonction ne doit en prendre aucun, et se lancé à partir du répertoire courant et de ces sou repertoires...
Aussi peut t-on remplacer -a par && et -o par || ?
Merci encore !
J'ai écris un algorithme, inspiré sur la fonction de asevere
fonction chercher()
debut
dossier = $1
Pour tous les éléments du dossier
Si (element est un fichier) et (element commence et fini par #) ou (element fini par ~) ou (élément commence par . et fini par ~)
supprimer $element
Sinon
Si $element est un repertoire
chercher() $element
fin si
fin si
fin
chercher () . // On oublie pas de lancer la recherche dans le repertoire courant
Si ca peut rendre les chose un peu plus claire ?
fonction chercher()
debut
dossier = $1
Pour tous les éléments du dossier
Si (element est un fichier) et (element commence et fini par #) ou (element fini par ~) ou (élément commence par . et fini par ~)
supprimer $element
Sinon
Si $element est un repertoire
chercher() $element
fin si
fin si
fin
chercher () . // On oublie pas de lancer la recherche dans le repertoire courant
Si ca peut rendre les chose un peu plus claire ?
Mon prof vient de me mailer, il faudrait utiliser la commande echo comme un vecteur de variable, j'ai essayer:
Je ne comprend pas ce qui ne vas pas, si vous voyez des modifications à effectuer n'hesitez pas !
function nettoyer (){
elus=$(echo * .*)
for elu in $elus;do
if [ -e $elu -a -d $elu -a $elu != ".." -a $elu != "." ]
then
cd $elu
nettoyer
else
if [ $elu=".*~" -o $elu="*#" -o $elu="*~" ]
then
rm $elu
fi
fi
done
}
Je ne comprend pas ce qui ne vas pas, si vous voyez des modifications à effectuer n'hesitez pas !
function nettoyer (){
elus=$(echo * .*)
for elu in $elus;do
if [ -e $elu -a -d $elu -a $elu != ".." -a $elu != "." ]
then
cd $elu
nettoyer
else
if [ $elu=".*~" -o $elu="*#" -o $elu="*~" ]
then
rm $elu
fi
fi
done
}
jipicy
Messages postés
40842
Date d'inscription
jeudi 28 août 2003
Statut
Modérateur
Dernière intervention
10 août 2020
4 897
9 mai 2007 à 19:16
9 mai 2007 à 19:16
Tiens un bout pour ton algo :
;-))
#! /bin/bash # Suppression fichier for file in *; do case $file in *~) rm -i $file # finissant par un tilde ;; \#*\#) rm -i $file # commençant et finissant par un dièse ;; esac done # Suppression fichier for file in .[!.]*~; do # commençant par un point et finissant par un tilde rm -i $file doneReste la fonction récursive à faire pour descendre dans les répertoires...
;-))
asevere
Messages postés
13084
Date d'inscription
lundi 28 janvier 2002
Statut
Webmaster
Dernière intervention
3 février 2022
426
9 mai 2007 à 21:49
9 mai 2007 à 21:49
Bonsoir,
Désolé, pas pu repasser hier et trop de boulot aujourd'hui.
Mon script (hormis le fait que les fichiers #*# m'avaient échappés) est faux :)
Pour le paramètre, je ne vois pas trop comment faire sans (pour initialiser la fonction récursive) l'appel se faisant dans le script, le script peut lui être appelé sans paramètre, mais l'erreur que j'ai corrigé au dessus a peut-être induit cette compréhension.
Pour le détails, JP à tout dit, c'est faisable sans la commande shopt bien sur, mais la l'option dotglob permet de n'avoir qu'un seul pattern à rechercher (*) et non (* .*), ceci dit, comme il y a aussi le pattern #*# c'est discutable. nullglob en revanche, cela permet de renvoyer une chaîne nulle en lieu et place de "*" si (*) ne match rien (pas de fichiers dans un sous dossier, que des fichiers cachés et pas de dotglob, etc.) ce qui évite donc des sorties d'erreur.
Mais j'ai plus simple/efficace :)
2 Recherche tout les fichiers/dossiers dans le répertoire courant
3 Vérification de l'existence du fichier par sécurité
4 type de l'élément: fichier
5 nom de l'élément correspondant à *~, .*~, #*#
10 Si ce n'est pas un fichier est-ce un répertoire (différent de lui-même et de son père)
11 Dans ce cas, on se place dedans et 12 on exécute a nouveau le script qui se trouve cette fois un cran au dessus
Il faut simplement savoir que $0 represente le shell lancé, donc:
./monscript lors de la première iteration (dans .)
.././monscript dans un repertoire enfant
../.././monscript dans un petit fils, etc.
Il y a quand même une grosse restriction, ce script doit être lancé via son chemin relatif, sinon ça ne marche pas, c'est d'ailleurs à ce niveau là que dirname/basename peuvent être utilisés
Quant au echo * tu peux remplacer la ligne 2 par les lignes suivantes:
Bon courage, @+
Désolé, pas pu repasser hier et trop de boulot aujourd'hui.
Mon script (hormis le fait que les fichiers #*# m'avaient échappés) est faux :)
#!/bin/sh function search_dir() { DIR=$1; for file in $DIR/*~; do if [ -f $file ]; then echo "Removing $file" echo "rm -f $file"; fi; done for element in $DIR/* ; do if [ -d $element -a $(basename $element) != ".." -a $(basename $element) != "." ]; then search_dir "$element"; fi; done; } shopt -s dotglob shopt -s nullglob search_dir ".";Celui ci contrairement à l'autre détruira les fichiers *~ dés le premier répertoire et pas que dans les sous répertoire du répertoire courant.
Pour le paramètre, je ne vois pas trop comment faire sans (pour initialiser la fonction récursive) l'appel se faisant dans le script, le script peut lui être appelé sans paramètre, mais l'erreur que j'ai corrigé au dessus a peut-être induit cette compréhension.
Pour le détails, JP à tout dit, c'est faisable sans la commande shopt bien sur, mais la l'option dotglob permet de n'avoir qu'un seul pattern à rechercher (*) et non (* .*), ceci dit, comme il y a aussi le pattern #*# c'est discutable. nullglob en revanche, cela permet de renvoyer une chaîne nulle en lieu et place de "*" si (*) ne match rien (pas de fichiers dans un sous dossier, que des fichiers cachés et pas de dotglob, etc.) ce qui évite donc des sorties d'erreur.
Mais j'ai plus simple/efficace :)
1 #!/bin/sh 2 for element in * .*; do 3 if [ -e $element ]; then 4 if [ -f $element ]; then 5 case $element in 6 *~ | \#*\# | .*~) 7 rm -f $element; 8 ;; 9 esac 10 elif [ -d $element -a $element != "." -a $element != ".." ]; then 11 cd $element 12 ../$0 13 cd - 14 fi; 15 fi; 16 done;
2 Recherche tout les fichiers/dossiers dans le répertoire courant
3 Vérification de l'existence du fichier par sécurité
4 type de l'élément: fichier
5 nom de l'élément correspondant à *~, .*~, #*#
10 Si ce n'est pas un fichier est-ce un répertoire (différent de lui-même et de son père)
11 Dans ce cas, on se place dedans et 12 on exécute a nouveau le script qui se trouve cette fois un cran au dessus
Il faut simplement savoir que $0 represente le shell lancé, donc:
./monscript lors de la première iteration (dans .)
.././monscript dans un repertoire enfant
../.././monscript dans un petit fils, etc.
Il y a quand même une grosse restriction, ce script doit être lancé via son chemin relatif, sinon ça ne marche pas, c'est d'ailleurs à ce niveau là que dirname/basename peuvent être utilisés
Quant au echo * tu peux remplacer la ligne 2 par les lignes suivantes:
elements=$(echo * .*) for element in $elementsmais l'intérêt est très limité, alors comme ça ne fait pas partie des consignes... :)
Bon courage, @+