Forum Programmation.shell utilisation de S_ISDIR et S_ISREG

Posté par  .
Étiquettes : aucune
0
7
sept.
2005
Bonjour, ô forum.

Dans mon post précédent, je me demandais comment tester si un objet présent dans un répertoire est un fichier ou un répertoire, sachant que j'écrivais un programme en bash.
Plus exactement, les deux tests que je veux écrire sont:
"si ce n'est pas un répertoire....."
"si ce n'est pas un fichier....."
En cherchant, j'ai fini pas trouver qu'il faut utiliser S_ISDIR et S_ISREG qui sont des macros décrites ici : http://www.linux-kheops.com/doc/man/manfr/man-html-0.9/man2/stat.2.(...)
Sauriez-vous comment il faut s"en servir?

Merci.
  • # Ben, man bash ...

    Posté par  . Évalué à 2.

    Ben il me semble que les tests que tu veux faire s'écrivent :

    for i in *
    do
    [ -d $i ] || echo "$i n'est pas un répertoire"
    [ -f $i ] || echo "$i n'est pas un fichier régulier"
    done

    Mais il me semble également avoir vu ce genre d'expression dans ton précédent script. Qu'est-ce qui ne fonctionne pas ?
    • [^] # Re: Ben, man bash ...

      Posté par  . Évalué à 2.

      D'autre part, les macros que tu cites sont écrites en C, et pas en shellscript. L'idée est que lorsque tu écris un programme en binaire, tu appelles une fois pour toutes stat() ou lstat() pour faire les contrôles sur ton fichier, et celui-ci te renvoie entre autre une liste de flags qui te donnent les infos que tu cherches.

      Les macros en question sont simplement là pour contrôler l'état de tel ou tel flag, sans que tu aies besoin de connaitre ceux-ci en particulier.
    • [^] # Re: Ben, man bash ...

      Posté par  . Évalué à 2.

      > Robin des Bulles

      En fait, dans mon script précédent, j'avais fait ceci :

      cd /home

      for a in * ; do
      # ignorer tous les objets qui ne sont pas des répertoires
      if [ ! -d "$a" ] ; then
      continue
      fi

      if [ "$a" = \* ] ; then
      break
      fi

      cd "/home/$a"

      for b in * ; do
      # ignorer tous les objets qui ne sont pas des fichiers
      if [ ! -e "$b" ] ; then
      continue
      fi

      if [ "$b" = \* ] ; then
      continue
      fi

      mais les tests sur les fichiers et les repertoires faisaient que le programme ne fonctionnaient pas bien. Je les ai donc supprimés.
      Sinon, ta solution est peut-être juste, mais je ne la comprends pas bien. Et en quoi est-elle différente de la mienne?
      • [^] # Re: Ben, man bash ...

        Posté par  . Évalué à 3.

        Manifestement, ton script n'est pas complet  : il manque les fins de boucles for.
        En plus:
        - le cd "/home/$a" à l'intérieur de la boucle change ton répertoire courant,
          il faut que tu reviennes au répertoire parent en fin de boucle.
        - les tests avec des continue ne simplifient pas la compréhension du script:
          ll vaut mieux inverser le test.
        - les tests [ $a = \* ] et [ $b = \* ] sont inutiles, voire faux:
           - soit $a vaut * parce que le répertoire /home est vide  et le test [ -d "$a" ] le traite correctement
           - soit $a vaut * parce /home contient un répertoire nommé *
             (ça peut arriver, les noms de fichiers peuvent contenir des métacaractères)
             et ton script va l'ignorer alors qu'il aurait dû le traiter.
        - si tu veux tester que $b est un fichier le test devrait être -f
          et non -e qui ne teste que l'existence et qui est vrai aussi
          pour un répertoire.
        
        cd /home
        
        for a in * ; do
            # traiter uniquement les répertoires
             if [ -d "$a" ] ; then
                 cd "/home/$a"
        
                 for b in * ; do
                     # traiter uniquement les fichiers
                     if [ -f "$b" ] ; then
                           # TRAITEMENT
                     fi
                done
            fi
            cd .. # retour au repertoire /home
        done
        
        • [^] # Re: Ben, man bash ...

          Posté par  . Évalué à 2.

          Arg ! Les balises ! :-\

          Bon la solution est quelque part dans la banquise du message précédent :

          [ -e "$a" ] teste l'existence d'un « objet » sur ton filesystem.

          [ -f "$a" ] teste si cette entrée est un fichier régulier ou pas.

          Bon courage.
          • [^] # Script achevé

            Posté par  . Évalué à 1.

            Ayé! Enfin!
            
            Je vous remercie tous pour vos contributions. En particulier la tienne, netsurfeur.
            Je suis épaté par la rapidité de vos réactions et la qualité de vos réponses. Si si!
            Donc j'ai terminé mon script et je le poste ici, sait-on jamais, ça pourrait servir à d'autres.
            
            Je rappelle à quoi il sert :
            Les employés d'une entreprise d'audit créés, chaque fois qu'une entreprise est auditée,
            un fichier contenant leur rapport sous /home/[le rep de l'auditeur]
            (ex : Jacques dépose ses rapports dans /home/Jacques).
            Le rapport est de la forme [nom de l'entreprise].extension (ex : Renault.doc).
            Le programme déplace les rapports des auditeurs et les place sous /Rapports/[nom de l'entreprise]
            (ex : le rapport renault.doc de Jacques sera placé sous /Rapports/Renault).
            Eventuellement, si l'entreprise est auditée pour la première fois
            (et qu'il n'y a donc pas encore de répertoire à son nom sous /Rapports),
            le programme créé un répertoire au nom de l'entreprise.
            Le premier rapport déposé prendra alors le nom, par exemple, Sony.001.doc.
            Si l'entreprise a été auditée plusieurs fois, le programme renomme le rapports en le déplaçant.
            Ainsi, le 2nd rapport sur Renault s'appellera Renault.002.doc, le 3ième, Renault.003.doc, etc...
            N'hésitez pas à me demandez des précisions si je n'ai pas été assez clair.
            
            ________________________________________________________________________________
            
            #! /bin/bash
            
            # Le programme suivant prend en compte un nombre illimité d'auditeurs et jusqu'à 999 rapports.
            # Les rapports sont traités quelque soit leur extension.
            # Le nom des rapports peut contenir n'importe quel signe y compris des espaces.
            # Le nom des rapports classés est de la forme 'société.001.ext'.
            # Le fait d'ajouter un point entre le nom de la société et le numéro permet de prendre
            # en compte la présence éventuelle de chiffres dans le nom de la société.
            
            # Variables :
            # a = répertoires des auditeurs sous /home
            # b = rapports non classés
            # c = nom de la société auditée
            # d = numéro du dernier rapport classé
            # e = extension du rapport
            
            cd "/home/Linux/Profils/"
            
            for a in * ; do
               # traiter uniquement les répertoires
               if [ -d "$a" ] ; then
                  cd "/home/Linux/Profils/$a"
              
                     for b in * ; do
                        # traiter uniquement les fichiers
                        if [ -f "$b" ] ; then
                           # on extrait du nom du rapport le nom de la société
                           # c'est à dire tout ce qui est avant le dernier point
                           c=${b%*.*}
                           # on récupère l'extension du rapport à classer
                           # c'est à dire tout ce qui est après le dernier point
                           e=.${b##*.}
                           # un répertoire au nom de la société existe-t-il déjà?
            	       cd "/home/Linux/Rapports"
                              if [ -d "$c" ] ; then
                                 cd "$c"
                                 # on extrait de la liste le dernier fichier ajouté
                                 # (celui dont le nombre est le plus grand)
                                 d=$(ls -1 | tail -1)
                                 # on retire au fichier son extension
                                 d=${d%*.*}
                                 # on extrait son numéro
                                 d=${d##*.}
                                 # on supprime les zéros non significatifs
                                 d=$(echo $d | sed 's/^0*//')
                                 # on incrémente ce numéro de 1
                                 d=$(($d + 1))
                                 # on lui accolle 2 '0'
                                 d=00$d
                                 # on extrait les 3 premiers chiffres (à partir de la droite)
                                 # \([0-9][0-9][0-9]\) et \1 : motif conservant les 3 chiffres de droite
                                 d=$(echo $d | sed 's/^0*\([0-9][0-9][0-9]\)/\1/g')
                                 # on déplace enfin le rapport du répertoire de l'auditeur
                                 # dans le répertoire de la société en le renommant
                                 mv "/home/Linux/Profils/$a/$b" "/home/Linux/Rapports/$c/$c"."$d$e"
                              else
                                 # on crée un répertoire au nom de la société
                                 mkdir "/home/Linux/Rapports/$c"
                                 # on y déplace alors le rapport en lui attribuant le numéro '001'
                                 mv "/home/Linux/Profils/$a/$b" "/home/Linux/Rapports/$c/$c".001"$e"
                              fi
            
                        fi
                           
            	    # le prog se trouvait alors dans /home/Linux/Rapports,
                        # il faut qu'il revienne dans le répertoire de l'auditeur
                        # pour traiter les rapports restant
                        cd "/home/Linux/Profils/$a"
            	      
            	 done
            
               fi
            
               # le prog se trouvait alors dans le répertoire d'un auditeur,
               # il faut qu'il revienne sous /home pour traiter les répertoires
               # des autres auditeurs
               cd "/home/Linux/Profils/"
            
            done
            • [^] # Re: Script achevé

              Posté par  (site web personnel) . Évalué à 1.

              Ca c'est pas malin:
              # Variables :
              # a = répertoires des auditeurs sous /home
              # b = rapports non classés
              # c = nom de la société auditée
              # d = numéro du dernier rapport classé
              # e = extension du rapport
              Aurait tu oublie la premiere maxime de la programmation utile:
              "utiliser des noms de variables significatifs"

              Autre chose:
              tu a du cd "/home/Linux/Profils/" partout dans ton script, typiquement
              une variable aurait ete tres utile au cas ou un changement du repertoire
              de base arriverait.

              Derniere chose:
              Les shells utilisents des alias pour permettrent aux utilisateurs
              de ne pas s'encombrer a retapper tout le temps les memes arguments
              mais dans un script il est bon de passer outres ceux ci pour eviter un
              maximum de comportement incoherents.
              De plus tout les unix non pas forcement les memes emplacements
              pour les commandes il est donc conseiller de creer des variables
              pour toutes les commandes utilisées.

              Ah et puis les cd dans un script c'est pas tres propre.

              ----------------------------------------------
              #! /bin/bash
              # Commandes
              LS=/bin/ls
              MV=/bin/mv
              SED=/bin/sed
              BASENAME=/usr/bin/basename
              TAIL=/usr/bin/tail
              MKDIR=/bin/mkdir

              # Variables :
              profils="/home/Linux/Profils"
              rapports="/home/Linux/Rapports"

              for auditeur in $profils/* ; do
              # traiter uniquement les répertoires
              if [ -d "$auditeur" ] ; then
              for doc in $auditeur/* ; do
              # traiter uniquement les fichiers
              if [ -f "$doc" ] ; then
              base=`$BASENAME $doc`
              # on extrait du nom du rapport le nom de la société
              # c'est à dire tout ce qui est avant le dernier point
              societe=${base%*.*}
              # on récupère l'extension du rapport à classer
              # c'est à dire tout ce qui est après le dernier point
              ext=.${base##*.}
              # un répertoire au nom de la société existe-t-il déjà?
              if [ -d "$rapports/$societe" ] ; then
              # on extrait de la liste le numero du dernier fichier ajouté
              # (celui dont le nombre est le plus grand)
              d=$($LS -1 "$rapports/$societe" | $TAIL -1 | sed 's/*\.\([0-9]+\)\.*/\1/g')
              # on incrémente ce numéro de 1
              # on lui accolle 2 '0'
              d=00$(($d + 1))
              # on extrait les 3 premiers chiffres (à partir de la droite)
              d=$(echo $d | sed 's/^0*\([0-9]\{3\}\)/\1/g')
              # on déplace enfin le rapport du répertoire de l'auditeur
              # dans le répertoire de la société en le renommant
              $MV "$doc" $rapports/$societe/$societe.$d$ext"
              else
              # on crée un répertoire au nom de la société
              $MKDIR "$rapports/$societe"
              # on y déplace alors le rapport en lui attribuant le numéro '001'
              $MV "$doc" "$rapports/$societe/$societe.001$ext"
              fi
              fi
              done
              fi
              done
              • [^] # Re: Script achevé

                Posté par  . Évalué à 2.

                Aurait tu oublie la premiere maxime de la programmation utile:
                "utiliser des noms de variables significatifs"

                Tout à fait d'accord
                tu a du cd "/home/Linux/Profils/" partout dans ton script, typiquement
                une variable aurait ete tres utile au cas ou un changement du repertoire
                de base arriverait.

                Là aussi, d'accord.
                D'ailleurs le script initial n'avait qu'un seul cd en absolu; les autres étaient relatifs. Il y avait donc moins besoin d'utiliser une variable pour le répertoire de base.
                De plus tout les unix non pas forcement les memes emplacements
                pour les commandes il est donc conseiller de creer des variables
                pour toutes les commandes utilisées.

                Pas d'accord du tout !
                Les emplacements peuvent être différents d'un unix à l'autre mais la variable PATH est là pour résoudre ce problème !
                Tu comptes éditer tous tes scripts un par un pour changer les chemins absolus des commandes le jour où tu migreras sur un autre unix ?
                • [^] # Re: Script achevé

                  Posté par  (site web personnel) . Évalué à 1.


                  Pas d'accord du tout !
                  Les emplacements peuvent être différents d'un unix à l'autre mais la variable PATH est là pour résoudre ce problème !
                  Tu comptes éditer tous tes scripts un par un pour changer les chemins absolus des commandes le jour où tu migreras sur un autre unix ?


                  Oui la variable PATH permet de s'affranchir de ce genre d'ennuis
                  mais pas du probleme des alias. Une solution peut etre de mixer
                  les deux choses en utilisant:
                  SED=`which sed`

Suivre le flux des commentaires

Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.