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 )
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.
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.
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é.
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
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 .
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
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.
@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%]!