Arrays, listas enlazadas y otras estructuras de datos en script cmd.exe (por lotes)

Estaba jugando con cmd.exe, pero en su ayuda no encontré ninguna información, cómo definir matrices.

He encontrado, cómo definir variables simples:

set a = 10 echo %a% 

Pero, quiero crear matrices, listas enlazadas, etc …

Entonces, ¿es capaz en cmd.exe (quiero decir: ¿en cmd.exe existe alguna matriz de palabras clave?)

Quiero realizar algunos algoritmos como:

  • ordenamiento de burbuja
  • ordenación rápida
  • tipo gnomo

etc …

Entonces, también quiero saber si Cmd.exe tiene referencias o instancias, estructuras, etc.

Porque su ayuda no está completa en: /?

¿Podría definirse CMD.exe como completo por la definición de Turing-Machine? (Turing-Completo)

De acuerdo. Trataré de ser lo más claro posible para no ser malentendido …

En los archivos Windows Batch, el nombre de una variable debe comenzar con una letra y puede incluir cualquier carácter válido, donde los caracteres válidos son: # $ ‘() * +, -.? @ [] _ ​​`{} ~ Además de letras y dígitos.

Esto significa que desde el punto de vista de cmd.exe, SET NORMAL_NAME=123 es exactamente igual que SET A#$'()*+,-.?@[\]_{}~=123 y también lo mismo que SET VECTOR[1]=123 ; las tres son variables normales. De esta manera, depende de usted escribir nombres de variables en forma de elementos de matriz:

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

De esta forma, echo %elem[2]% mostrará Second one .

Si desea utilizar otra variable como índice, debe saber que la sustitución de variables incluidas en símbolos de porcentaje por sus valores se analiza de izquierda a derecha ; esto significa que:

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

no da el resultado deseado porque significa: muestra el valor de la variable elem[ variable, seguida de i , seguida del valor de ] .

Para resolver este problema, debe usar Expansión retrasada , es decir, insertar el comando setlocal EnableDelayedExpansion al principio, incluir las variables de índice en símbolos de porcentaje y encerrar los elementos de la matriz en signos de exclamación:

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

También puede usar los parámetros de los comandos FOR como índices: for /L %%i in (1,1,3) do echo !elem[%%i]! . Debe usar! Index! para almacenar valores en elementos de la matriz cuando el índice se cambia dentro de un FOR o IF: set elem[!index!]=New value . Para obtener el valor de un elemento cuando el índice cambia dentro de FOR / IF, encierre el elemento en dos símbolos de porcentaje y preceda al comando con una call . Por ejemplo, para mover un rango de elementos de la matriz cuatro lugares a la izquierda:

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

Otra forma de lograr el proceso anterior es usar un comando FOR adicional para cambiar la expansión retrasada del índice por un parámetro reemplazable equivalente, y luego usar la expansión retardada para el elemento del arreglo. Este método se ejecuta más rápido que CALL anterior:

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

De esta forma, el archivo por lotes se comporta como si administrara arreglos. Creo que el punto importante aquí no es discutir si Batch maneja arreglos o no, sino el hecho de que puede administrar matrices en archivos por lotes de una manera equivalente a otros lenguajes de progtwigción.

 @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% 

Tenga en cuenta que los valores de índice no están limitados a números, sino que pueden ser cualquier cadena que contenga caracteres válidos; este punto permite definir lo que en otros lenguajes de progtwigción se llaman matrices asociativas . En esta respuesta hay una explicación detallada del método utilizado para resolver un problema utilizando una matriz asociativa. Tenga en cuenta también que el espacio es un carácter válido en los nombres de las variables, por lo que debe prestar atención para no insertar espacios en los nombres de las variables que pueden pasar desapercibidos.

Expliqué las razones por las que tengo que usar la notación de matriz en los archivos por lotes en esta publicación .

En esta publicación hay un archivo por lotes que lee un archivo de texto y almacena los índices de las líneas en un vector, luego hace una clase Buble de elementos vectoriales basados ​​en los contenidos de la línea; el resultado equivalente es una clasificación sobre el contenido del archivo.

En esta publicación hay una aplicación básica de Base de datos relacionales en Lote basada en índices almacenados en archivos.

En esta publicación hay una aplicación completa de listas enlazadas en Batch que ensambla una gran estructura de datos tomada de un subdirectorio y la muestra en forma de comando TREE.

Las secuencias de comandos de shell de Windows realmente no están diseñadas para funcionar con matrices, y mucho menos estructuras de datos complejas. En su mayor parte, todo es una cadena en el shell de Windows, pero hay algunas cosas que puede hacer para “trabajar con” matrices, como declarar n variables VAR_1, VAR_2, VAR_3... usando un bucle y filtrando en el prefijo VAR_ , o creando una cadena delimitada y luego usando la construcción FOR que itera sobre una cadena delimitada.

Del mismo modo, puede usar la misma idea básica para crear un conjunto de variables tipo ITEM_NAME, ITEM_DATA como ITEM_NAME, ITEM_DATA o w / e. Incluso encontré este enlace que habla de simular una matriz asociativa en CMD.

Es todo terriblemente hackish e inconveniente cuando se trata de eso. El shell de línea de comandos simplemente no fue diseñado para una progtwigción pesada. Estoy de acuerdo con @MatteoItalia: si necesita secuencias de comandos serias, use un lenguaje de scripting real.

Hablando en serio: nunca escuché que ese lote tiene arreglos, quizás puedas emularlos con algún truco extraño, pero no lo llamaría una buena idea.

Las referencias / instancias / estructuras son elementos para un lenguaje real, las secuencias de comandos cmd son solo un conjunto de extensiones que crecieron sobre el intérprete muy primitivo que era command.com, puedes hacer algunas secuencias de comandos básicas, pero algo más complicado que un montón de llamadas a otros comandos están condenados a volverse feos e incomprensibles.

La única construcción “avanzada” es el bucle raro de hacer todo, que, mezclado con las extrañas “reglas” de sustitución de variables ( %var% , %%var !var! Son cosas diferentes debido al analizador idiota ), hace que escribir incluso algoritmos triviales sea una colección de hacks extraños (ver, por ejemplo, aquí para una implementación de quicksort ).

Mi consejo es, si quieres hacer tus scripts de una manera sensata, utiliza un lenguaje de scripting real , y deja el lote para hacks simples y rápidos y para compatibilidad con versiones anteriores.

Hice una implementación de ordenación de burbujas en lotes utilizando pseudo-matrices hace un tiempo. No estoy seguro de por qué lo usaría (aunque lo admitiré en otro archivo de proceso por lotes) ya que el tamaño de la lista aumenta bastante lentamente. Fue más para ponerme un pequeño desafío. Alguien puede encontrar esto útil.

 :: 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 

Con respecto a esta statement:

He encontrado, cómo definir variables simples:

 set a = 10 echo %a% 

¡Esto simplemente está mal! La variable a permanecerá vacía (suponiendo que estaba vacía inicialmente) y echo %a% devolverá que ECHO is on. Una variable llamada ESPACIO se establecerá en realidad en el valor SPACE 10 .

Entonces, para que el código funcione, debe deshacerse de los ESPACIOS alrededor del signo de igual a igual:

 set a=10 echo %a% 

Para hacer que la asignación sea segura contra todos los caracteres, use la syntax citada (suponiendo que tenga las extensiones de comando habilitadas, que es la predeterminada para el símbolo del sistema de Windows de todos modos):

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

Para el rest de su pregunta, recomiendo leer la excelente y completa respuesta de Aacini .

El siguiente progtwig simula las operaciones de vectores (matrices) en cmd . Las subrutinas presentadas en él se diseñaron inicialmente para algunos casos especiales, como almacenar los parámetros del progtwig en una matriz o recorrer los nombres de los archivos en un bucle ” for ” y almacenarlos en una matriz. En estos casos, en un bloque de enabled delayed expansion , los caracteres ” ! ” – si están presentes en los valores de los parámetros o en el valor de la variable de ciclo ” for ” – serían interpretados. Es por eso que, en estos casos, las subrutinas se deben usar dentro de un bloque de disabled delayed expansion :

 @echo off rem The subroutines presented bellow implement vectors (arrays) operations in CMD rem Definition of a vector : 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 ) 

También es posible almacenar los parámetros del progtwig en una “matriz” o recorrer los nombres de los archivos en un directorio usando un bucle ” for ” y almacenarlos en una “matriz” (sin interpretar ” ! ” En sus valores) sin usar el subrutinas en el progtwig de arriba:

 @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 

No hay matrices, listas vinculadas, matrices asociativas en el lote de Windows. Existe, sin embargo, la syntax más arcana, extraña, contra-intuitiva con la que me he encontrado alguna vez. En serio, necesitas usar un lenguaje de scripting real para esto. Cualquier cosa menos lote.

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