在cmd.exe(批处理)脚本中的数组,链表和其他数据结构

我正在玩cmd.exe,但在其帮助中,我没有find任何信息,如何定义数组。

我发现,如何定义简单的variables:

set a = 10 echo %a% 

但是,我想创build数组,链表等…

那么,它是否能够在cmd.exe中(我的意思是:在cmd.exe中是否存在任何数组关键字?)

我想要实现一些algorithm:

  • 冒泡sorting
  • 快速sorting
  • 侏儒sorting

等等…

所以,我也想知道,Cmd.exe是否有引用或实例,结构等?

导致其帮助不完整在:/?

图灵机定义可以将Cmd.exe定义为完整吗? (图灵完成)

好。 我会尽可能的清楚,不要被误解

在Windowsbatch file中, variables名应该以字母开头,可以包含任何有效的字符,其中有效的字符是:#$'()* +, – 。?@ [] _`{}〜除了字母和数字。

这意味着从cmd.exe的angular度来看, SET NORMAL_NAME=123SET A#$'()*+,-.?@[\]_{}~=123完全相同,也与SET VECTOR[1]=123 ; 所有这三个都是正常variables。 这样, 就可以用数组元素的forms写variables名了:

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

这样, echo %elem[2]%将显示Second one

如果要使用另一个variables作为索引,则必须知道用百分号表示的variables的值由左向右分析; 这意味着:

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

没有给出想要的结果,因为这意味着:显示elem[variables,后面是i ,后面跟着variables的值]值。

为了解决这个问题,你必须使用Delayed Expansion ,即在开头插入setlocal EnableDelayedExpansion命令,将索引variables用百分号括起来,并将数组元素括入感叹号中:

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

你也可以使用FOR命令的参数作为索引: for /L %%i in (1,1,3) do echo !elem[%%i]! 。 你必须使用!索引! 在索引在FOR或IF内部更改时将值存储在数组元素中: set elem[!index!]=New value 。 要在FOR / IF内部索引更改时获取元素的值,请将元素放在两个百分号符号中,并在call之前放置该命令。 例如,要将一系列数组元素左移四个位置:

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

实现上一个过程的另一种方法是使用额外的FOR命令,通过等效的可replace参数更改索引的延迟扩展,然后使用数组元素的延迟扩展。 此方法比以前的CALL运行速度更快:

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

这样,batch file的行为就像pipe理数组一样。 我认为这里的重点不是讨论批处理是否pipe理数组,而是可以用其他编程语言的等价方式pipe理batch file中的数组。

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

请注意,索引值不限于数字,但可以是包含有效字符的任何string; 这一点允许定义其他编程语言称为关联数组 。 在这个答案中有一个关于使用关联数组解决问题的方法的详细解释。 还要注意,空格在variables名中是一个有效的字符,所以你必须注意不要在可能被忽略的variables名中插入空格。

我详细阐述了在这篇文章中我必须在batch file中使用数组符号的原因。

在这篇文章中有一个batch file,它读取一个文本文件并将这些行的索引存储在一个向量中,然后根据行内容执行一个Buble向量元素sorting; 等效的结果是对文件内容的sorting。

在这篇文章中 ,基于存储在文件中的索引,在批处理中有一个基本的关系数据库应用程序。

在这篇文章中 ,Batch中有一个完整的多连接列表应用程序,它组装一个从子目录中取得的大数据结构,并以TREE命令的forms显示它。

严肃地说:我从来没有听说过批量有arrays,也许你可以用一些奇怪的技巧来模拟他们,但我不会说这是个好主意。

参考资料/实例/结构是一个真正的语言的东西,CMD脚本只是一个扩展,在原始的解释器是command.com,你可以做一些基本的脚本,但比一堆调用其他命令注定变得丑陋和不可理解。

唯一的“高级”构造是循环的怪圈,它与variablesreplace的奇怪“规则”( %var%%%var!var! ,因为白痴parsing器),使得甚至可以将一些奇怪的黑客algorithm(比如在这里用于实现快速sorting )写成一些微不足道的algorithm。

我的提示是,如果你想以一种理智的方式进行脚本编程,可以使用一种真正的脚本语言,并留下一些批注,以便进行简单,快速的入侵以及向后兼容。

Windows shell脚本实际上不是用来处理数组,更不用说复杂的数据结构了。 在大多数情况下,一切都是在Windowsshell的string,但是,有一些事情可以做“处理”数组,如声明nvariablesVAR_1, VAR_2, VAR_3...使用循环和过滤前缀VAR_ ,或者创build一个分隔string,然后使用迭代分隔string的FOR构造。

类似地,你可以使用相同的基本思想来创build一个类似于结构的variables,如ITEM_NAME, ITEM_DATA或w / e。 我什至发现这个链接 ,谈论模拟CMD中的关联数组。

当它归结于它时,这是非常恶劣和不方便的。 命令行shell只是不适合繁重的编程。 我同意@MatteoItalia – 如果你需要严肃的脚本,使用真正的脚本语言。

前段时间我使用伪数组批量实现了一个气泡sorting实现。 不知道为什么你会使用它(虽然我会承认这样做在另一个batch file),因为它变得很慢,随着名单的大小增加。 这更多的是给自己一个小小的挑战。 有人可能会觉得这很有用。

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

下面的程序模拟向量(数组)在cmd操作。 其中提供的子程序最初是为某些特殊情况devise的,如将程序参数存储在数组中,或循环遍历“ for ”循环中的文件名并将其存储在数组中。 在这些情况下,在已enabled delayed expansion块中,将会解释“ ! ”字符(如果出现在参数值或“ for ”循环variables的值中)。 这就是为什么在这种情况下,子程序必须在disabled delayed expansion块中使用:

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

也可以使用“ for ”循环通过目录中的文件名将程序参数存储在“数组”或循环中,并将它们存储在“数组”中(不需要解释其值中的“ ! ”),而不使用所提供的上面程序中的子程序:

 @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 

关于这个声明:

我发现,如何定义简单的variables:

 set a = 10 echo %a% 

这简直是​​错的! variablesa将保持为空(假设它最初是空的)并且echo %a%将返回ECHO is on. 一个名为SPACE的variables实际上将被设置为值SPACE 10

所以要使代码工作,你必须摆脱等号的空格

 set a=10 echo %a% 

要使分配对所有字符安全,请使用带引号的语法(假设您已启用命令扩展 ,无论如何这是Windows命令提示符的默认设置):

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

对于你所有问题的其他问题,我build议阅读Aacini伟大而全面的答案 。

Windows批处理中没有数组,链接列表和关联数组。 然而,我所遇到过的最神秘,最古怪的反直觉语法。 严重的是,你需要使用一个真正的脚本语言。 除了批处理。

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