Tableaux, listes liées et autres structures de données dans cmd.exe (lot) script

je jouais avec cmd.exe, mais dans son aide je n'ai pas trouvé d'info, comment définir les tableaux.

j'ai trouvé, comment définir des variables simples:

set a = 10
echo %a%

Mais, je veux créer des tableaux, liste, etc...

ainsi, est-il capable dans cmd.exe ( je veux dire: est-ce dans cmd.exe existe aucun tableau de mots-clés? )

je veux réaliser quelques algorithmes comme:

  • tri à bulles
  • tri rapide
  • gnome sort

etc...

donc, je veux aussi savoir, Cmd.exe avez-vous des références ou des instances, des structures, etc.?

faire en sorte que son aide n'est pas pleine: /?

Pourrait Cmd.exe être défini comme complet par Turing-Machine définition? (Turing-Complete )

54
demandé sur aschipfl 2012-04-16 01:42:04

8 réponses

Ok. Je vais essayer d'être aussi clair que possible pour ne pas être mal compris...

dans les fichiers de lot de Windows un nom de la variable doit commencer par une lettre et peut inclure n'importe quel caractère valide, où caractères valides sont: #$'()*+,-.?@[]_`{}~ outre les lettres et les chiffres.

cela signifie que du cmd.exe point de vue, SET NORMAL_NAME=123 est exactement la même que SET A#$'()*+,-.?@[\]_{}~=123 et aussi le même que SET VECTOR[1]=123 ; toutes les trois sont des variables normales. De cette façon, c'est à vous d'écrire des noms de variables sous forme d'éléments de tableau:

set elem[1]=First element
set elem[2]=Second one
set elem[3]=The third one

par ici, echo %elem[2]% montrera Second one .

si vous voulez utiliser une autre variable comme indice, vous devez savoir que le remplacement des variables contenues dans les symboles de pourcentage par leurs valeurs est écrit de gauche à droite ; cela signifie que:

set i=2
echo %elem[%i%]%

ne donne pas le résultat souhaité car il signifie: afficher la valeur de la variable elem[ , suivie de i , suivie de la valeur de la variable ] .

pour résoudre ce problème, vous devez utiliser delayed Expansion , c'est-à-dire insérer la commande setlocal EnableDelayedExpansion au début, enfermer les variables de l'indice dans les symboles de pourcentage, et enfermer les éléments du tableau aux points d'exclamation:

setlocal EnableDelayedExpansion
set elem[1]=First element
set elem[2]=Second one
set elem[3]=The third one
set i=2
echo !elem[%i%]!

vous pouvez également utiliser les paramètres de pour les commandes comme index: for /L %%i in (1,1,3) do echo !elem[%%i]! . Vous devez utiliser !index! pour stocker des valeurs dans des éléments de tableau lorsque l'index est modifié à l'intérieur de a pour ou si: set elem[!index!]=New value . Pour obtenir la valeur d'un élément lorsque l'index change à L'intérieur pour/IF, entourez l'élément dans les symboles de double pour cent et précédez la commande avec call . Par exemple, pour déplacer une gamme d'éléments de tableau quatre endroits à gauche:

for /L %%i in (%start%,1,%end%) do (
   set /A j=%%i + 4
   call set elem[%%i]=%%elem[!j!]%%
)

une autre façon de réaliser le processus précédent est d'utiliser une commande supplémentaire FOR pour modifier l'extension retardée de l'index par un paramètre remplaçable équivalent, puis d'utiliser l'extension retardée pour l'élément du tableau. Cette méthode fonctionne plus rapidement que L'appel précédent:

for /L %%i in (%start%,1,%end%) do (
   set /A j=%%i + 4
   for %%j in (!j!) do set elem[%%i]=!elem[%%j]!
)

de cette façon, le fichier de lot se comporte comme il gère des tableaux. Je pense que le point important ici n'est pas de discuter si Batch gère les tableaux ou non, mais le fait que vous pouvez gérer les tableaux dans les fichiers Batch d'une manière équivalente d'autres langages de programmation.

@echo off
setlocal EnableDelayedExpansion

rem Create vector with names of days
set i=0
for %%d in (Sunday Monday Tuesday Wednesday Thrusday Friday Saturday) do (
   set /A i=i+1
   set day[!i!]=%%d
)

rem Get current date and calculate DayOfWeek
for /F "tokens=1-3 delims=/" %%a in ("%date%") do (
   set /A mm=10%%a %% 100, dd=10%%b %% 100, yy=%%c
)
if %mm% lss 3 set /A mm=mm+12, yy=yy-1
set /A a=yy/100, b=a/4, c=2-a+b, e=36525*(yy+4716)/100, f=306*(mm+1)/10, jdn=c+dd+e+f-1523, dow=jdn %% 7 + 1
echo Today is !day[%dow%]!, %date%

notez que les valeurs d'index ne sont pas limitées aux nombres, mais qu'elles peuvent être n'importe quelle chaîne qui contient des caractères valides; ce point permet de définir ce que dans d'autres langages de programmation sont appelés tableaux associatifs . À cette réponse Il ya une explication détaillée de la méthode utilisée pour résoudre un problème en utilisant un tableau associatif. Notez également que l'espace est un caractère valide dans les noms de variables, vous devez donc faire attention à ne pas insérer d'Espaces Dans les noms de variables qui peuvent passer inaperçus.

j'ai expliqué les raisons pour lesquelles je dois utiliser la notation de tableau dans les fichiers de lot à ce post .

Dans ce post il y a un fichier de commandes qui lit un fichier texte et stocke l'index de les lignes dans un vecteur, font alors une sorte de bulle d'éléments vectoriels basés sur le contenu de la ligne; le résultat équivalent est une sorte sur le contenu du fichier.

Dans ce post il y a une base de Données Relationnelle de la Base de l'application dans le Lot basée sur des indices de référence stockées dans des fichiers.

Dans ce post il y a plusieurs liste liée application dans le Lot qui rassemble une grande structure de données prises à partir d'un sous-répertoire et l'affiche sous la forme de la commande TREE.

138
répondu Aacini 2017-05-23 11:54:50

Windows shell scripting n'est vraiment pas conçu pour fonctionner avec des tableaux, encore moins des structures de données complexes. Pour la plupart, tout est une chaîne dans le shell windows, mais il y a des choses que vous pouvez faire pour "travailler avec" des tableaux, comme déclarer n variables VAR_1, VAR_2, VAR_3... en utilisant une boucle et en filtrant sur le préfixe VAR_ , ou en créant une chaîne délimitée , puis en utilisant la construction FOR qui itère sur une chaîne délimitée.

De même, vous pouvez utiliser la même idée de base pour créer un ensemble de variables comme ITEM_NAME, ITEM_DATA ou w/E. J'ai même trouvé ce lien qui parle de simuler un réseau associatif dans CMD.

tout cela est terriblement hackish et incommode quand il vient à elle. Le shell de ligne de commande n'a pas été conçu pour une programmation lourde. Je suis d'accord avec @MatteoItalia -- si vous avez besoin de scripts sérieux, utilisez un vrai langage de script.

7
répondu trutheality 2012-04-15 22:01:21

sérieusement parlant: je n'ai jamais entendu que le lot a des tableaux, peut-être que vous pouvez les émuler avec quelque tour étrange, mais je ne dirais pas que c'est une bonne idée.

références / instances/structures sont des trucs pour un vrai langage, cmd scripting est juste un tas d'extensions qui a grandi sur l'interpréteur très primitif qui a été command.com, vous pouvez faire quelques scripts de base, mais n'importe quoi de plus compliqué qu'un tas d'appels à d'autres commandes est condamné à devenir laid et incompréhensible.

la seule construction "avancée" est le do-it-all weirdo for boucle, qui, mélangé avec l'étrange "règles" de la substitution variable( %var% , %%var , !var! , sont différentes choses en raison de l'analyseur idiot), rend l'écriture des algorithmes même trivial un recueil de hacks étranges (voir par exemple ici pour une mise en œuvre de quicksort ).

mon conseil est, si vous voulez faire votre script d'une manière saine, utilisez un réel langage de script, et de laisser le Lot Pour simple, rapide hacks et pour rétrocompatibilité.

6
répondu Matteo Italia 2017-05-23 12:10:26

j'ai fait une implémentation de tri de bulles en lot en utilisant des pseudo-tableaux il y a un moment. Pas sûr pourquoi vous l'utilisez (bien que je vais admettre de le faire dans un autre fichier batch) car il devient assez lent que la taille de la liste augmente. Il était plus de me suis fixé un petit défi. Quelqu'un pourrait trouver cela utile.

:: Bubblesort
:: Horribly inefficient for large lists
:: Dave Johnson implementation 05/04/2013
@echo off
setlocal enabledelayedexpansion
:: Number of entries to populate and sort
set maxvalue=50
:: Fill a list of vars with Random numbers and print them
for /l %%a in (1,1,%maxvalue%) do (
    set /a tosort%%a=!random!
)
:: echo them
set tosort
:: Commence bubble sort
Echo Sorting...
set /a maxvalue-=1
set iterations=0
for /l %%a in (%maxvalue%,-1,1) do ( REM Decrease by 1 the number of checks each time as the top value will always float to the end
    set hasswapped=0
        for /l %%b in (1,1,%%a) do (
            set /a next=%%b+1
            set next=tosort!next!
            set next=!next!
            call :grabvalues tosort%%b !next!
            rem echo comparing tosort%%b = !tosortvalue! and !next! = !nextvalue!
            if !nextvalue! LSS !tosortvalue! (
            rem set /a num_of_swaps+=1
            rem echo Swapping !num_of_swaps!
                set !next!=!tosortvalue!
                set tosort%%b=!nextvalue!
                set /a hasswapped+=1
            )
        )
    set /a iterations+=1
    if !hasswapped!==0 goto sorted
)
goto:eof
:grabvalues
set tosortvalue=!%1!
set nextvalue=!%2!
goto:eof
:sorted
::nice one our kid
set tosortvalue=
echo Iterations required: %iterations%
set tosort
endlocal
6
répondu Dave_J 2014-03-05 10:14:53

concernant cette déclaration:

j'ai trouvé, comment définir des variables simples:

set a = 10
echo %a%

C'est tout simplement faux! La Variable a restera vide (à supposer qu'elle ait été vide au départ) et echo %a% retournera ECHO is on. une variable appelée a espace sera effectivement réglée à la valeur espace 10 .

donc pour que le code fonctionne, vous devez vous débarrasser du espaces autour du signe égal-

set a=10
echo %a%

pour rendre l'affectation sûre contre tous les caractères, Utilisez la syntaxe Citée (en supposant que vous avez la commande extensions activée, qui est la valeur par défaut pour l'invite de commande Windows de toute façon):

set "a=1&0"
echo(%a%

pour le reste de votre question, je vous recommande de lire Aacini 's grande et complète réponse .

4
répondu aschipfl 2017-07-30 19:18:21

le programme suivant simule les opérations des vecteurs (tableaux) dans cmd . Les sous-routines qui y sont présentées ont d'abord été conçues pour des cas particuliers comme le stockage des paramètres du programme dans un tableau ou le bouclage des noms de fichiers dans une boucle " for " et leur stockage dans un tableau. Dans ces cas, dans un bloc enabled delayed expansion , les caractères ! " - s'ils sont présents dans les valeurs des paramètres ou dans la valeur de la variable de boucle for " - seraient interprétés. C'est pourquoi, dans ces cas, les sous-programmes doivent être utilisés à l'intérieur d'un disabled delayed expansion bloc:

@echo off

rem The subroutines presented bellow implement vectors (arrays) operations in CMD

rem Definition of a vector <v>:
rem      v_0 - variable that stores the number of elements of the vector;
rem      v_1..v_n, where n=v_0 - variables that store the values of the vector elements.


rem :::MAIN START:::

setlocal disabledelayedexpansion

    rem Getting all the parameters passed to the program in the vector 'params':
    rem Delayed expansion is left disabled in order not to interpret "!" in the program parameters' values (%1, %2, ... );
    rem If a program parameter is not quoted, special characters in it (like "^", "&", "|") get interpreted at program launch.
:loop1
    set "param=%~1"
    if defined param (
        call :VectorAddElementNext params param
        shift
        goto :loop1
    )
    rem Printing the vector 'params':
    call :VectorPrint params

    pause&echo.

    rem After the vector variables are set, delayed expansion can be enabled and "!" are not interpreted in the vector variables's values:
    echo Printing the elements of the vector 'params':
    setlocal enabledelayedexpansion
        if defined params_0 (
            for /l %%i in (1,1,!params_0!) do (
                echo params_%%i="!params_%%i!"
            )
        )
    endlocal

    pause&echo.

    rem Setting the vector 'filenames' with the list of filenames in the current directory:
    rem Delayed expansion is left disabled in order not to interpret "!" in the %%i variable's value;
    for %%i in (*) do (
        set "current_filename=%%~i"
        call :VectorAddElementNext filenames current_filename
    )
    rem Printing the vector 'filenames':
    call :VectorPrint filenames

    pause&echo.

    rem After the vector variables are set, delayed expansion can be enabled and "!" are not interpreted in the vector variables's values:
    echo Printing the elements of the vector 'filenames':
    setlocal enabledelayedexpansion
        if defined filenames_0 (
            for /l %%i in (1,1,!filenames_0!) do (
                echo filenames_%%i="!filenames_%%i!"
            )
        )
    endlocal

    pause&echo.

endlocal
pause

rem :::MAIN END:::
goto :eof


:VectorAddElementNext
rem Vector Add Element Next
rem adds the string contained in variable %2 in the next element position (vector length + 1) in vector %1
(
    setlocal enabledelayedexpansion
        set "elem_value=!%2!"
        set /a vector_length=%1_0
        if not defined %1_0 set /a vector_length=0
        set /a vector_length+=1
        set elem_name=%1_!vector_length!
)
(
    endlocal
    set "%elem_name%=%elem_value%"
    set %1_0=%vector_length%
    goto :eof
)

:VectorAddElementDVNext
rem Vector Add Element Direct Value Next
rem adds the string %2 in the next element position (vector length + 1) in vector %1
(
    setlocal enabledelayedexpansion
        set "elem_value=%~2"
        set /a vector_length=%1_0
        if not defined %1_0 set /a vector_length=0
        set /a vector_length+=1
        set elem_name=%1_!vector_length!
)
(
    endlocal
    set "%elem_name%=%elem_value%"
    set %1_0=%vector_length%
    goto :eof
)

:VectorAddElement
rem Vector Add Element
rem adds the string contained in the variable %3 in the position contained in %2 (variable or direct value) in the vector %1
(
    setlocal enabledelayedexpansion
        set "elem_value=!%3!"
        set /a elem_position=%2
        set /a vector_length=%1_0
        if not defined %1_0 set /a vector_length=0
        if !elem_position! geq !vector_length! (
            set /a vector_length=elem_position
        )
        set elem_name=%1_!elem_position!
)
(
    endlocal
    set "%elem_name%=%elem_value%"
    if not "%elem_position%"=="0" set %1_0=%vector_length%
    goto :eof
)

:VectorAddElementDV
rem Vector Add Element Direct Value
rem adds the string %3 in the position contained in %2 (variable or direct value) in the vector %1
(
    setlocal enabledelayedexpansion
        set "elem_value=%~3"
        set /a elem_position=%2
        set /a vector_length=%1_0
        if not defined %1_0 set /a vector_length=0
        if !elem_position! geq !vector_length! (
            set /a vector_length=elem_position
        )
        set elem_name=%1_!elem_position!
)
(
    endlocal
    set "%elem_name%=%elem_value%"
    if not "%elem_position%"=="0" set %1_0=%vector_length%
    goto :eof
)

:VectorPrint
rem Vector Print
rem Prints all the elements names and values of the vector %1 on sepparate lines
(
    setlocal enabledelayedexpansion
        set /a vector_length=%1_0
        if !vector_length! == 0 (
            echo Vector "%1" is empty!
        ) else (
            echo Vector "%1":
            for /l %%i in (1,1,!vector_length!) do (
                echo [%%i]: "!%1_%%i!"
            )
        )
)
(
    endlocal
    goto :eof
)

:VectorDestroy
rem Vector Destroy
rem Empties all the elements values of the vector %1
(
    setlocal enabledelayedexpansion
        set /a vector_length=%1_0
)
(
    endlocal
    if not %vector_length% == 0 (
        for /l %%i in (1,1,%vector_length%) do (
            set "%1_%%i="
        )
        set "%1_0="
    )
    goto :eof
)

il est également possible de stocker les paramètres du programme dans un "tableau" ou une boucle à travers les noms de fichiers dans un répertoire en utilisant une " for " boucle et les stocker dans un "tableau" (sans interpréter " ! "dans leurs valeurs) sans utiliser les sous-programmes présentés dans le programme ci-dessus:

@echo off

setlocal disabledelayedexpansion

    rem Getting all the parameters passed to the program in the array 'params':
    rem Delayed expansion is left disabled in order not to interpret "!" in the program parameters' values (%1, %2, ... );
    rem If a program parameter is not quoted, special characters in it (like "^", "&", "|") get interpreted at program launch.
    set /a count=1
:loop1
    set "param=%~1"
    if defined param (
        set "params_%count%=%param%"
        set /a count+=1
        shift
        goto :loop1
    )
    set /a params_0=count-1

    echo.

    rem After the array variables are set, delayed expansion can be enabled and "!" are not interpreted in the array variables's values:
    rem Printing the array 'params':
    echo Printing the elements of the array 'params':
    setlocal enabledelayedexpansion
        if defined params_0 (
            for /l %%i in (1,1,!params_0!) do (
                echo params_%%i="!params_%%i!"
            )
        )
    endlocal

    pause&echo.

    rem Setting the array 'filenames' with the list of filenames in the current directory:
    rem Delayed expansion is left disabled in order not to interpret "!" in the %%i variable's value;
    set /a count=0
    for %%i in (*) do (
        set "current_filename=%%~i"
        set /a count+=1
        call set "filenames_%%count%%=%%current_filename%%"
    )
    set /a filenames_0=count

    rem After the array variables are set, delayed expansion can be enabled and "!" are not interpreted in the array variables's values:
    rem Printing the array 'filenames':
    echo Printing the elements of the array 'filenames':
    setlocal enabledelayedexpansion
        if defined filenames_0 (
            for /l %%i in (1,1,!filenames_0!) do (
                echo filenames_%%i="!filenames_%%i!"
            )
        )
    endlocal

endlocal
pause

goto :eof
2
répondu 2016-11-02 13:02:23

il n'y a pas de tableaux, listes liées, tableaux associatifs dans Windows batch. Il y a, cependant, la syntaxe la plus obscure, bizarre, contre-intuitive que j'ai jamais rencontré. Sérieusement, tu dois utiliser un vrai langage de script pour ça. Tout sauf La Fournée.

-1
répondu David Heffernan 2012-04-15 22:03:14
@echo off

set array=

setlocal ENABLEEXTENSIONS ENABLEDELAYEDEXPANSION

set nl=^&echo(

set array=auto blue ^!nl!^
  bycicle green ^!nl!^
  buggy   red

echo convert the String in indexed arrays

set /a index=0

for /F "tokens=1,2,3*" %%a in ( 'echo(!array!' ) do (

 echo(vehicle[!index!]=%%a color[!index!]=%%b 
 set vehicle[!index!]=%%a
 set color[!index!]=%%b
 set /a index=!index!+1   

)

echo use the arrays

echo(%vehicle[1]% %color[1]%
echo oder

set index=1
echo(!vehicle[%index%]! !color[%index%]!
-3
répondu tux 2016-11-02 11:53:11