Différence commande DOS FOR entre XP et 7

Résolu
Bonjour,

Je suis en train d'écrire un fichier de commandes DOS et je bute sur un problème de différence de comportement de la commande FOR selon que le batch est exécuté sous Windows XP SP3 ou Seven.

Voici la commande :
for /f "tokens=2, 3, 4,5,6,7,8,9 delims= " %%A in ('fsutil fsinfo drives') Do (
echo %%A %%B %%C %%D %%E %%F %%G %%H
)

Exécution sous Seven :
la commande echo m'affiche : C:\ E:\ F:\ G:\ H:\ I:\ j:\ K:\
et la commande fsutil fsinfo drives exécutée à l'invite de commande m'affiche :
Lecteurs : C:\ E:\ F:\ G:\ H:\ I:\ J:\ K:\
C'est tout bon :-))

Exécution sous XP SP3 :
la commande echo m'affiche : C:\
et la commande fsutil fsinfo drives exécutée à l'invite de commande m'affiche :
Lecteurs : C:\ E:\ F:\ G:\ H:\ I:\ J:\ (il n'y a pas de lecteur K: sur ce PC)
Et alors là ! :-((
La commande FOR ne me transmet, semble-t-il, que le "tokens 2" mais pas les suivants !?.

Ca fait plusieurs jours que je suis bloqué là-dessus et je suis sec.
Si quelqu'un avait une petite idée je suis preneur.

Bernard

19 réponses

  • Votes
  • Date
  • Date décroissante
Résumé de la discussion

Le fil traite d'un problème avec FOR /F et tokens lors de l'interrogation de fsutil fsinfo drives, XP SP3 ne transmettant que le premier token alors que Seven restitue tous les lecteurs. Plusieurs réponses recommandent d'échapper le caractère pipe et d'utiliser TOKENS=* avec MORE dans la commande FOR, ce qui permet de récupérer toutes les valeurs renvoyées par FSUTIL FSINFO DRIVES. D'autres solutions évoquent l'emploi de sed ou d'outils GNU pour Windows, ou l'écriture du résultat dans un fichier temporaire avant lecture par FOR, pour contourner les limites de l'analyse directe.

Bobot (l’IA à votre service)
  1. j'aime bien la réponse de dubeck avec la commande more, ca marche super bien.
    seulement j'ai eu un problème : j'avais besoin de parse le résultat de :

    FSUTIL FSINFO DRIVES | MORE

    sans passer par un fichier temporaire.
    problème, la commande FOR /F n'accepte pas "directement" de pipe dans son paramétrage.
    après quelques recherches, voila la solution :
    (il suffit d'escape le caractère "|" qui sert a pipe, et d'un coup, ça marche)

    FOR /F "TOKENS=*" %%A IN ('FSUTIL FSINFO DRIVES^| MORE') DO ( 
    ECHO %%A 
    )

    %%A renvoie successivement n valeurs, autant que de lecteurs (car il y a n lignes dans l'output de la commande)
    attention a coder un truc pour récuperer %%A a chaque boucle.
    Et voila, plus besoin de fichier temporaire pour stocker le résultat

    PS : on peut appliquer la même chose en utilisant le SED.

    PS2 : je ne sais pas si d'autre commandes renvoie des résultats avec des "NUL" en plein milieu, mais potentiellement ca marchera pareil
    1. @Pierrot6150,

      Je ne sais comment te remercier. Tout est comme je voulais et ça fonctionne sous XP et 7.
      En tout cas, chapeau ! Je trouve ce batch brillantissime.

      Bon week-end et au plaisir,
      Bernard
      1. Bonjour Pierrot6150,

        Je vais abuser une dernière fois (j'espère de tes grandes compétences et te solliciter à nouveau. Dans la procédure _VolumeIsIntegre j'ai essayé d'ajouter l'affichage du résultat de fsutil dirty query !Lecteur! pour chaque lecteur (le lecteur est intègre / le lecteur n'est pas intègre). Je n'y suis pas arrivé :-((

        Bernard
        1. Modifier le prg pour ajouter les 3 lignes en gras.

          @echo off
          echo. Lister lecteur fixe du PC
          echo.

          SETLOCAL ENABLEDELAYEDEXPANSION
          for %%I in (A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z) do (
          set Data=%%I:
          set Lecteur=!Data:~0,2!
          call :_Check_Drive
          )

          echo.
          echo. Terminer
          pause
          exit

          :_Check_Drive
          fsutil fsinfo drivetype !Lecteur! | find "Lecteur fixe" >nul
          rem Si tu veux de l'affichage...
          rem if %errorlevel% equ 0 fsutil fsinfo drivetype !Lecteur! && call :_VolumeIsIntegre
          rem Ici pas d'affichage.
          if %errorlevel% equ 0 call :_VolumeIsIntegre
          goto :EOF

          :_VolumeIsIntegre
          rem Vérifier si le volume est intègre.
          rem La recherche ce fait sur le volume n'est pas intègre.
          fsutil dirty query !Lecteur! | find "n'est pas" >nul
          set /a Resultat=%errorlevel%
          fsutil dirty query !Lecteur!
          if !Resultat! equ 0 chkdsk !Lecteur! /F /R

          goto :EOF
      2. Bonjour,

        "C'est plutôt le contraire, si le HDD n'est pas intègre qu'il faut faire une réparation par CHKDSK"
        Euh, oui... J'étais un peu fatigué hier soir :-))

        Je te remercie pour ton script. Je vais le tester mais franchement je suis complètement largué, c'est du batch de haut niveau :-))

        Bonne journée,
        Bernard
        1. Je reviens pour faire appel à Pierrot6150. Je voulais modifier le script mais je suis complètement largué. C'est une manière de coder du batch que je ne connais pas.

          Après avoir déterminé si un lecteur est fixe, je vaudrais savoir si "le lecteur est intègre" avec une commande fsutil dirty query <lecteur> et s'il est intègre lancer un checkdsk <lecteeur>
          .

          Pierrot6150, merci par avance de ton aide.
          Bernard
          1. Salut,
            C'est plutôt le contraire, si le HDD n'est pas intègre qu'il faut faire une réparation par CHKDSK.

            :_Check_Drive
            fsutil fsinfo drivetype !Lecteur! | find "Lecteur fixe" >nul
            rem Si tu veux de l'affichage...
            rem if %errorlevel% equ 0 fsutil fsinfo drivetype !Lecteur! && call :_VolumeIsIntegre
            rem Ici pas d'affichage.
            if %errorlevel% equ 0 call :_VolumeIsIntegre
            goto :EOF

            :_VolumeIsIntegre
            rem Vérifier si le volume est intègre.
            rem La recherche ce fait sur le volume n'est pas intègre.
            fsutil dirty query !Lecteur! | find "n'est pas" >nul
            if %errorlevel% equ 0 chkdsk !Lecteur! /F /R
            goto :EOF
        2. Et merci également à Pierrot6150 pour sa solution qui fonctionne aussi bien sous Seven qu'XP, et que je vais peut-être adopter parce qu'elle ne nécessite pas d'installer un module supplémentaire (sed.exe).

          Bernard
          1. A part mon plantage ("Pas de disque") on peut considérer que le problème pour lequel j'ai ouvert le sujet est réglé (grâce au fameux "sed").

            Je vais quand même tester la solution de Pierrot6150, ajouter un commentaire et clore le sujet.

            En tout cas merci pour ton aide qui m'a mis sur la voie dès ta première réponse.

            Au plaisir,
            Bernard
            1. Pas de problème ça m'a fait très plaisir d'avoir pu aider.

              Bon alors bonne suite @++
          2. Bonsoir "Bricomachin",

            J'ai découvert sed récemment. C'est une commande d'origine Unix qui a été développé (comme des tas d'autres commandes) pour Windows. Tout ce que j'en sais au jour d'aujourd'hui c'est qu'elle permet, entre autres choses, de remplacer des chaînes de caractère avec possibilité de coder de l'hexadécimal.

            Ce qui donne donc pour mon problème ;
            fsutil fsinfo drives | sed s/\x0/" "/g >%TEMP%\disques.txt
            for /f "skip=1 tokens=2,3,4,5,6,7,8 delims= " %%A in (%TEMP%\disques.txt) Do (...

            On dirige le résultat du fsutil dans un fichier texte en ayant au passage (enchaînement par le "pipe" |) remplacé les NUL x0 par des espaces " 3.
            Le fichier est ensuite repris dans la commande FOR pour récupérer chaque lecteur.

            Tu peux récupérer les "GNU utilities for Win32" ici : http://unxutils.sourceforge.net/ Tu prends le fichier UnxUpdates.zip, l'autre lien se plante. Tu mets les outils dont tu as besoin dans %Windir%\System32.

            Bernard
            1. ça a vraiment l'aire bien... je télécharge tout de suite...
              À part ça tu n'as donc plus besoin d'aide ... ?
          3. Hello ribotb,

            Donc pour le ^@ ça correspond à Crtl + @ dans l'invité de commande... Je sais je n'ai pas été très clair désolé. Lorsque tu tape Ctrl + une touche il s'écrit : ^Touche... Si tu tape Ctrl+ G (^G) et ENTER ça fait beeep ! Donc quand j'ai trouvé la table ASSCI avec les touches "Ctrl + Touche" et que j'ai vu que NUL était répertorié et que c'était Ctrl +@ dans l'invité de commande, je me suis dis que ça irai mais je n'avais pas réfléchi au fait que @ n'est pas une touche de base... et donc que je ne pouvais faire Crtl+@ vu que c'est Ctrl + (AltGr +2) vu que pour faire @ chez moi c'est AltGr +2 (ça dépend des claviers...) donc cette possibilité tombe à l'eau désolé...

            Et puis pour le |more, ce n'est pas moi qui est répondu :p mais je n'ai pas compris non-plus ^^ Le mec a l'air calé et je ne connais pas assez l'hexa et tout ça pour donner mon point de vue...

            Maintenant, à moi de poser une question :
            C'est quoi un sed ^^' ?
            ...

            Bricomachin
            1. Bonsoir Bricomachin,

              J'ai essayé avec ^@ et ^G mais ça n'a rien donné. Et je n'ai pas compris ta dernière suggestion : l'utilisation de more.

              Par contre je suis en train de mettre au point un sed pour remplacer le NUL (x00) par l'espace (x20).

              Bonne soirée,
              Bernard
              1. J'ai trouvé d'où vient le problème/ J'ai examiné le fichier en sortie du fsutil avec un éditeur hexadécimal et j'ai vu que le séparateur entre les lecteurs était différent entre XP et Seven.

                Sous Seven le séparateur est l'espace (20 en hexa).

                Sous XP le séparateur est NUL (00 en hexa) !

                Problème : comment coder NUL dans le "delims=" de la commande FOR ?

                Bernard
                1. ouahou là c'était une idée de génie ! chapeau !
                  Essaye de faire un simple copier-coller du fichier texte généré avec
                  fsutil etc... >fichier.txt
                  .
                  Tu l'ouvre avec le bloc-note, si ça ne marche pas, avc notepad++ qui, je crois, permet de voir toutes ces petites subtilités d'un code ^^
                2. J'ai trouvé je crois : essaye de taper
                  ^@
                  dans le cmd.C'est le signe pour NUL tout comme taper
                  ^G
                  fait un bref bip sonore... Maintenant pour trouver le caractère correspondant on pourrait faire :
                  echo ^@>test.txt
                  C'est comme ça que j'ai défini le caractère qui fait bip dans un batch...

                  source :http://www.table-ascii.com/
                3. Contributeur
                  hllo
                  en ajoutant more , les \0 sont transformés en sauts de ligne 0x0a 0x0d
                  fsutil fsinfo drives | more | od -x
                  000000 0a0d 654c 7463 7565 7372 3aff 4320 5c3a
                  000020 0a0d 3a44 0d5c 0d0a 0d0a 000a
                  000033
              2. Bonjour "Bricomachin",

                J'ai repris les tests ce matin. En ce qui concerne tes dernières suggestions :

                fsutil fsinfo drives>disques.txt
                for /f "tokens=2, 3, 4,5,6,7,8,9 delims= " %%A in (disques.txt) Do (
                echo %%A %%B %%C %%D %%E %%F %%G %%H
                )
                C'est quelque chose que j'avais essayé mais qui ne donne toujours pas le résultat escompté. Le contenu du fichier est bon mais la commande FOR ne récupère pas les lecteurs.

                for /f "tokens=2-9 delims= " %%A in ('fsutil fsinfo drives') Do (
                echo %%A %%B %%C %%D %%E %%F %%G %%H
                )
                On ne récupère que C:\

                Merci quand même pour tes suggestions.
                Bonne journée,
                Bernard
                1. Et ceci ???

                  @echo off
                  echo. Lister lecteur fixe du PC
                  echo.

                  SETLOCAL ENABLEDELAYEDEXPANSION
                  for %%I in (A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z) do (
                  set Data=%%I:
                  set Lecteur=!Data:~0,2!
                  call :_Check_Drive
                  )

                  echo.
                  echo. Terminer
                  pause
                  exit

                  :_Check_Drive
                  fsutil fsinfo drivetype !Lecteur! | find "Lecteur fixe" >nul
                  if %errorlevel% equ 0 fsutil fsinfo drivetype !Lecteur!
                  goto :EOF
              3. Et si tu fais ça, ça marche ?:
                fsutil fsinfo drives>disques.txt  
                for /f "tokens=2, 3, 4,5,6,7,8,9 delims= " %%A in (disques.txt) Do (  
                echo %%A %%B %%C %%D %%E %%F %%G %%H  
                ) 
                (Essayons de voir si ça bug car on utilise une sortie de commande...)
                Un petit merci fait toujours plaisir ainsi qu'une orthographe correcte.
                Les posts ont eux aussi droit à une retraite ! Pensez à mettre votre sujet en résolu :p
                1. Et comme ça ?:
                  for /f "tokens=2-9 delims= " %%A in ('fsutil fsinfo drives') Do (  
                  echo %%A %%B %%C %%D %%E %%F %%G %%H  
                  )
              4. En remplaçant les ' par des ' l'echo nous dit...

                fsinfo drive

                !? (ça, c'est de moi :-))
                1. ouais c'est parce qu'il analyse "fsutil fsinfo drives" et pas la sortie. Tu pourrais essayer d'enregistrer le résultat dans une variable puis d'analyser la variable non ?
              5. Salut,

                Ahhhhh illumination soudaine ! Mais je me trompe peut-être :p

                Essaie comme ça:
                for /f "usebackq tokens=2, 3, 4,5,6,7,8,9 delims= " %%A in ('fsutil fsinfo drives') Do (
                echo %%A %%B %%C %%D %%E %%F %%G %%H
                ) 


                J'ai remplacé les ' par des ' (guillemets simples inverses)...

                En espérant ne pas passer pour un c** :p,

                Bricomachin
                1. Finalement en me relisant je me dis que je vais vraiment passer pour un c** ^^
              6. Voilà docteur :-))

                1. ça se plante > " * delims= " était innatendu

                2. affiche > C:\

                3. affiche > a:C:\ b: g:%G

                4. affiche > b:
                1. Salut,

                  Essaye ces 4 possibilités sur xp et poste les résultats stp on pourra analyser ce qui se passe :
                  1:
                  for /f "tokens=2, * delims= " %%A in ('fsutil fsinfo drives') Do (
                  echo %%A %%B
                  ) 
                  2:
                  for /f "tokens=2, 3, 4,5,6,7,8,9 delims= " %%A in ('fsutil fsinfo drives') Do (
                  echo %%A %%B
                  ) 
                  3:
                  for /f "tokens=2,7 delims= " %%A in ('fsutil fsinfo drives') Do (
                  echo a:%%A b:%%B  g:%%G
                  ) 
                  4:
                  for /f "tokens=2, 3, 4,5,6,7,8,9 delims= " %%A in ('fsutil fsinfo drives') Do (
                  echo b:%%B
                  ) 

                  Je pense que lorsque ce sera fait on aura une meilleure vision de se qui se passe avec la commande sur xp. Je me souviens que j'avais eu le problème sur xp pour une liste de films à trier mais comme j'ai passé sur 7 j'ai simplifié le prog en utilisant les fonctions 7 donc je n'ai plus le prog de base. Je vais essayer de me souvenir... :p

                  @+

                  Bricomachin
                  1. Bonsoir,
                    Oui, j'ai besoin de (presque) tous les lecteurs. Dans la suite du scrit j'analyse chaque lecteur avec fsutil fsinfo drivetype <lecteur> pour trouver les lecteurs fixes.
                    Ca marche avec Windows 7 mais pas avec XP, c'est ça que je ne comprends pas.

                    Bernard
                    1. Hello,

                      Est-ce que tu as besoin de récupérer les nom de lecteur ?
                      Si non tu peux écrire ta commande ainsi :
                      for /f "tokens=2, * delims= " %%A in ('fsutil fsinfo drives') Do (
                      echo %%A %%B
                      )
                      

                      Et si oui ben... je réfléchis, je réfléchis promis :p

                      Bricomachin