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

58 windows arrays cmd batch-file delayedvariableexpansion

我正在玩cmd.exe,但在它的帮助下我没有找到任何信息,如何定义数组.

我发现,如何定义简单变量:

set a=10
echo %a%
Run Code Online (Sandbox Code Playgroud)

但是,我想创建数组,链表等...

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

我想实现一些算法:

  • 泡泡排序
  • 快速排序
  • 侏儒排序

等等...

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

导致其帮助不完整:/?

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

Aac*_*ini 163

好.我会尽量保持清醒,不要被误解......

在Windows批处理文件中,变量名称应以字母开头,并且可以包含任何有效字符,其中有效字符为:#$'()*+, - .?@ [] _` {}〜除了字母和数字.

这意味着从cmd.exe的角度来看,SET NORMAL_NAME=123是完全相同的SET A#$'()*+,-.?@[\]_{}~=123,也是一样的SET VECTOR[1]=123; 这三个都是正常变量.这样,可以以数组元素的形式编写变量名称:

set elem[1]=First element
set elem[2]=Second one
set elem[3]=The third one
Run Code Online (Sandbox Code Playgroud)

这样,echo %elem[2]%就会显示出来Second one.

如果要将另一个变量用作索引,则必须知道用百分比符号括起来的变量替换值从左到右进行解析; 这意味着:

set i=2
echo %elem[%i%]%
Run Code Online (Sandbox Code Playgroud)

没有给出所需的结果,因为它意味着:显示elem[变量的值,后跟i,后跟]变量的值.

要解决此问题,必须使用延迟扩展,即setlocal EnableDelayedExpansion在开头插入命令,将索引变量括在百分比符号中,并将数组元素括在感叹号中:

setlocal EnableDelayedExpansion
set elem[1]=First element
set elem[2]=Second one
set elem[3]=The third one
set i=2
echo !elem[%i%]!
Run Code Online (Sandbox Code Playgroud)

您也可以使用FOR命令的参数作为索引:for /L %%i in (1,1,3) do echo !elem[%%i]!.你必须使用!index!在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!]%%
)
Run Code Online (Sandbox Code Playgroud)

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

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

这样,批处理文件的行为就像管理数组一样.我认为重要的一点是不讨论Batch是否管理数组,而是你可以用其他编程语言的等效方式管理Batch文件中的数组.

@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%
Run Code Online (Sandbox Code Playgroud)

请注意,索引值不限于数字,但它们可以是包含有效字符的任何字符串; 这一点允许定义其他编程语言中称为关联数组的内容.在这个答案中,详细解释了使用关联数组解决问题的方法.另请注意,空格是变量名称中的有效字符,因此您必须注意不要在变量名称中插入可能未被注意的空格.

我在这篇文章中详细说明了我必须在批处理文件中使用数组表示法的原因.

这篇文章中有一个Batch文件,它读取文本文件并将行的索引存储在向量中,然后根据行内容执行Buble Sort of vector元素; 等效的结果是文件内容的排序.

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

这篇文章中,Batch中有一个完整的多链表列表应用程序,它组装了一个从子目录中获取的大型数据结构,并以TREE命令的形式显示它.


tru*_*ity 8

Windows shell脚本实际上并不适用于数组,更不用说复杂的数据结构了.在大多数情况下,一切都是windows shell中的一个字符串,但是,你可以做一些事情来"使用"数组,比如使用循环声明n变量VAR_1, VAR_2, VAR_3...并对前缀进行过滤VAR_,或者创建一个分隔的字符串然后使用FOR构造迭代分隔的字符串.

类似地,您可以使用相同的基本思想来创建类似结构的变量集,例如ITEM_NAME, ITEM_DATA或w/e.我甚至发现这个链接谈到了在CMD中模拟关联数组.

归结为它,这一切都非常严重和不方便.命令行shell只是不适合繁重的编程.我同意@MatteoItalia - 如果您需要严肃的脚本,请使用真正的脚本语言.

  • @magesi CMD确实有一件事 - "FOR"命令.如果您真的想学习CMD,请掌握并继续学习. (2认同)

Dav*_*e_J 6

我刚才使用伪数组批量生成了冒泡排序.不确定为什么要使用它(虽然我会承认在另一个批处理文件中这样做),因为随着列表大小的增加它变得非常慢.更多的是为自己设置一个小挑战. 有人可能会觉得这很有用.

:: 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
Run Code Online (Sandbox Code Playgroud)

  • @Aacini:绝对有这样的事情.当您使用不以语法或语义提供数组结构的语言模拟数组时,可以清楚明确地将这些数组称为"伪数组". (3认同)

Mat*_*lia 5

说真的:我从来没有听说过批处理有数组,也许你可以用一些奇怪的技巧来模仿它们,但我不会称之为好主意.

引用/实例/结构是真正的语言的东西,cmd脚本只是在一个非常原始的解释器(即command.com)上增长的一堆扩展,你可以做一些基本的脚本,但比一堆调用更复杂其他命令注定要变得难看和难以理解.

唯一的"先进"的构造是做它,所有的怪人for环,它与变量替换的奇怪"规则"混合(%var%,%%var,!var!,是因为愚蠢的解析器的不同的东西),使得编写甚至琐碎的算法集合奇怪的黑客(参见此处的quicksort实现).

我的提示是,如果您想以理智的方式编写脚本,请使用真正的脚本语言,并将批处理留给简单,快速的黑客和向后兼容.


asc*_*pfl 5

关于此声明:

我发现了如何定义简单变量:

set a = 10
echo %a%
Run Code Online (Sandbox Code Playgroud)

这是完全错误的!变量a将保持为空(假设最初为空)并echo %a%返回,实际上将被ECHO is on.称为的变量aSPACE设置为value SPACE10

因此,要使代码正常工作,您必须摆脱SPACEs等于号的包围:

set a=10
echo %a%
Run Code Online (Sandbox Code Playgroud)

为了使分配对所有字符都是安全的,请使用引用的语法(假设您已启用命令扩展名,这始终是Windows命令提示符的默认设置):

set "a=1&0"
echo(%a%
Run Code Online (Sandbox Code Playgroud)

对于其余所有问题,我建议您阅读Aacini的详尽综合解答