我在玩cmd.exe,但是在它的帮助下我没有找到任何信息,如何定义数组。
我发现了如何定义简单变量:
set a=10
echo %a%
但是,我想创建数组,链表等。
因此,它在cmd.exe中是否可以(我的意思是:cmd.exe中是否存在任何数组关键字?)
我想实现一些算法为:
- 气泡排序
- 快速排序
- 侏儒排序
等等...
所以,我也想知道,Cmd.exe是否具有引用或实例,结构等?
导致其帮助未满:/?
Turing-Machine定义能否将Cmd.exe定义为完整?(图灵完成)
我在玩cmd.exe,但是在它的帮助下我没有找到任何信息,如何定义数组。
我发现了如何定义简单变量:
set a=10
echo %a%
但是,我想创建数组,链表等。
因此,它在cmd.exe中是否可以(我的意思是:cmd.exe中是否存在任何数组关键字?)
我想实现一些算法为:
等等...
所以,我也想知道,Cmd.exe是否具有引用或实例,结构等?
导致其帮助未满:/?
Turing-Machine定义能否将Cmd.exe定义为完整?(图灵完成)
Answers:
好。我会尽量清楚一点,不要被误解...
在Windows Batch文件中,变量名应以字母开头,并且可以包含任何有效字符,其中有效字符为:#$'()* +,-。?@ [] _`{}〜除字母和数字外。
这意味着从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
这样,echo %elem[2]%将显示Second one。
如果要使用另一个变量作为索引,则必须知道,用百分号括起来的变量用其值替换是从左到右进行解析的;这意味着:
set i=2
echo %elem[%i%]%
无法给出理想的结果,因为这意味着:显示elem[变量的值,然后显示i,然后显示变量的值]。
要解决此问题,必须使用Delayed Expansion,即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%]!
您也可以将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!]%%
)
实现先前过程的另一种方法是使用附加的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]!
)
这样,批处理文件的行为就像管理数组一样。我认为这里的重点不是讨论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%
请注意,索引值不限于数字,而是可以是包含有效字符的任何字符串。这一点允许定义其他编程语言中的什么称为关联数组。在此答案中,将详细介绍用于使用关联数组解决问题的方法。还要注意,空格是变量名中的有效字符,因此必须注意不要在变量名中插入可能不被注意的空格。
我在这篇文章中详细说明了我必须在Batch文件中使用数组符号的原因。
在这篇文章中有一个批处理文件,该文件读取文本文件并将行的索引存储在向量中,然后根据行内容对向量元素进行Buble Sort;等效的结果是对文件内容进行排序。
在这篇文章有基于存储在文件索引在批处理基本关系数据库应用程序。
在这篇文章中,Batch中有一个完整的多个链表应用程序,该应用程序组装了一个从子目录获取的大型数据结构,并以TREE命令的形式显示。
=&<NUL>(0x00)以外的任何字符都是有效的变量名,甚至包括换行符
set "var:=value"和echo %var:%有效,但是如果您在冒号后插入任何字符,则无法访问变量值(因为%var%扩展扩展规则)
Windows Shell脚本实际上并不是设计用于数组,更不用说复杂的数据结构了。在大多数情况下,一切都是Windows shell中的字符串,但是,您可以做一些事情来“处理”数组,例如使用循环声明n变量VAR_1, VAR_2, VAR_3...并过滤前缀VAR_,或者创建定界字符串,然后使用FOR在定界字符串上迭代的构造。
同样,您可以使用相同的基本思想来创建类似structITEM_NAME, ITEM_DATA或w / e的类似结构的变量集。我什至发现了这个链接,它讨论了如何在CMD中模拟关联数组。
归根结底,这都是非常骇人听闻的,而且很不方便。命令行shell并不是为繁重的编程而设计的。我同意@MatteoItalia-如果您需要认真的脚本编写,请使用真正的脚本编写语言。
FOR命令。如果您真的想学习CMD,请掌握它并继续前进。
cmd.exeWine项目中的问题。:)
不久前,我使用伪数组批量创建了冒泡排序实现。不知道为什么要使用它(尽管我会在另一个批处理文件中使用它),因为随着列表大小的增加它会变得很慢。给自己设置一些挑战更多。 有人可能会觉得这很有用。
:: 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
set /A命令吗?在此示例中:set /A resul=9+6,您将如何调用存储在变量中的15 字符串resul?“伪数”?“模拟整数”?请记住,批处理文件并没有提供数字变量!
set /A,也没有要求批处理。我只是说,世界上肯定有“伪数组”这样的概念。Dave似乎在描述什么,就像一组PHP变量一样$var1 = 0; $var2 = 1; $var3 = 2; $i = 2; echo ${var$i};。那是数组吗?否。是否尝试模拟数组?是。这是一个伪数组。这就是“伪”的意思。
认真地说:我从来没有听说过批处理包含数组,也许您可以用一些奇怪的技巧来模仿它们,但是我不会把它称为一个好主意。
引用/实例/结构是一种真实语言的东西,cmd脚本只是一堆扩展,这些扩展是在command.com这个非常原始的解释器上扩展的,您可以执行一些基本的脚本编写,但是比一堆调用要复杂得多其他命令注定会变得丑陋和令人费解。
唯一的“高级”结构是do-it-all weirdofor循环,它与变量替换的奇怪“规则”(%var%,%%var,!var!,是因为愚蠢的解析器的不同的东西),使得编写甚至琐碎的算法集合奇怪的骇客(请参阅此处的quicksort实现)。
我的提示是,如果您想以一种明智的方式进行脚本编写,请使用一种真正的脚本语言,并保留批处理功能,以进行简单,快速的破解并向后兼容。
for循环分割。就像我说的那样,存在set/ forhack的集合。在这种情况下,您会做严肃的事情吗?
for是的,该命令与您将获得的命令差不多。和一起工作是多么痛苦。
以下程序模拟中的向量(数组)操作cmd。它中提供的子例程最初是为某些特殊情况设计的,例如将程序参数存储在数组中或在“ for”循环中遍历文件名并将它们存储在数组中。在这些情况下,在一个enabled delayed expansion块中,将对“ !”字符(如果存在于参数值或“ for”循环变量的值中)进行解释。这就是为什么在这种情况下,必须在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
TLDR:
我想到了使用“ For”循环和“ set”命令来解析变量的想法,使我能够创建伪数组,包括有序和链表样式,更重要的是,类似于结构的伪对象。
典型的批处理伪数组,以及如何解析:
SET "_Arr.Names="Name 1" "Name 2" ... "Name N""
FOR %A IN (%_Arr.Names%) DO @( Echo.%~A )
REM Results:
REM Name 1
REM Name 2
REM ...
REM Name N
在下面,我们制作了一些哑伪数组和手动有序伪数组,并创建了一个有序伪数组来捕获DIR命令的输出。
我们还将采用哑哑伪数组并将其转换为有序数组(之后删除原始的哑哑伪数组变量)。
然后,我们更新所有有序数组以手动包含更多元素。
最后,我们通过对值7到9进行预定义的For L循环并生成一个随机值以打印数组的第4个示例值,来动态报告数组中的某些值。
注意:
我创建了一个变量来保存添加成员的方法,以使添加成员更加简单。
我指出这一点是因为它应该很容易看到我们如何使从有序数组到伪对象的次要跳转。
@(
SETLOCAL ENABLEDELAYEDEXPANSION
ECHO OFF
REM Manually Create a shortcut method to add more elements to a specific ordered array
SET "_Arr.Songs.Add=SET /A "_Arr.Songs.0+=1"&&CALL SET "_Arr.Songs.%%_Arr.Songs.0%%"
REM Define some 'dumb' Pseudo arrays
SET "_Arr.Names="Name 1" "Name 2" "Name 3" "Name 4" "Name 5" "Name 6" "Name 7" "Name 8""
SET "_Arr.States="AL" "AK" "AZ" "AR" "CA" "CO" "CT" "DE" "FL" "GA" "HI" "ID" "IL" "IN" "IA" "KS" "KY" "LA" "ME" "MD" "MA" "MI" "MN" "MS" "MO" "MT" "NE" "NV" "NH" "NJ" "NM" "NY" "NC" "ND" "OH" "OK" "OR" "PA" "RI" "SC" "SD" "TN" "TX" "UT" "VT" "VA" "WA" "WV" "WI" "WY""
)
REM Manually Create One Ordered Array
%_Arr.Songs.Add%=Hey Jude"
%_Arr.Songs.Add%=The Bartman"
%_Arr.Songs.Add%=Teenage Dirtbag"
%_Arr.Songs.Add%=Roundabout"
%_Arr.Songs.Add%=The Sound of Silence"
%_Arr.Songs.Add%=Jack and Diane"
%_Arr.Songs.Add%=One Angry Dwarf and 200 Solumn Faces"
REM Turn All Pre-Existing Normal Pseudo Arrays into Element Arrays
REM Since Ordered Arrays use Index 0, we can skip any manually created Ordered Arrays:
FOR /F "Tokens=2 Delims==." %%A IN ('SET _Arr. ^| FIND /V ".0=" ^| SORT') DO (
IF /I "%%~A" NEQ "!_TmpArrName!" (
SET "_TmpArrName=%%~A"
IF NOT DEFINED _Arr.!_TmpArrName!.Add (
REM Create a shortcut method to add more members to the array
SET "_Arr.!_TmpArrName!.Add=SET /A "_Arr.!_TmpArrName!.0+=1"&&CALL SET "_Arr.!_TmpArrName!.%%_Arr.!_TmpArrName!.0%%"
)
FOR %%a IN (!_Arr.%%~A!) DO (
CALL SET /A "_Arr.!_TmpArrName!.0+=1"
CALL SET "_Arr.!_TmpArrName!.%%_Arr.!_TmpArrName!.0%%=%%~a"
)
)
IF DEFINED _Arr.!_TmpArrName! (
REM Remove Unneeded Dumb Psuedo Array "_Arr.!_TmpArrName!"
SET "_Arr.!_TmpArrName!="
)
)
REM Create New Array of unknown Length from Command Output, and Store it as an Ordered Array
SET "_TmpArrName=WinDir"
FOR /F "Tokens=* Delims==." %%A IN ('Dir /B /A:D "C:\Windows"') DO (
IF NOT DEFINED _Arr.!_TmpArrName!.Add (
SET "_Arr.!_TmpArrName!.Add=SET /A "_Arr.!_TmpArrName!.0+=1"&&CALL SET "_Arr.!_TmpArrName!.%%_Arr.!_TmpArrName!.0%%"
)
CALL SET /A "_Arr.!_TmpArrName!.0+=1"
CALL SET "_Arr.!_TmpArrName!.%%_Arr.!_TmpArrName!.0%%=%%~A"
)
)
REM Manually Add additional Elements to the Ordered Arrays:
%_Arr.Names.Add%=Manual Name 1"
%_Arr.Names.Add%=Manual Name 2"
%_Arr.Names.Add%=Manual Name 3"
%_Arr.States.Add%=51st State"
%_Arr.States.Add%=52nd State"
%_Arr.States.Add%=53rd State"
%_Arr.Songs.Add%=Live and Let Die"
%_Arr.Songs.Add%=Baby Shark"
%_Arr.Songs.Add%=Safety Dance"
%_Arr.WinDir.Add%=Fake_Folder 1"
%_Arr.WinDir.Add%=Fake_Folder 2"
%_Arr.WinDir.Add%=Fake_Folder 3"
REM Test Output:
REM Use a For Loop to List Values 7 to 9 of each array and A Psuedo Rnadom 4th value
REM We are only interested in Ordered Arrays, so the .0 works nicely to locate those exclusively.
FOR /F "Tokens=2,4 Delims==." %%A IN ('SET _Arr. ^| FIND ".0=" ^| SORT') DO (
CALL :Get-Rnd %%~B
ECHO.
ECHO.%%~A 7 to 9, Plus !_Rnd#! - Psuedo Randomly Selected
FOR /L %%L IN (7,1,9) DO (
CALL Echo. * Element [%%L] of %%~A Pseudo Array = "%%_Arr.%%~A.%%L%%"
)
CALL Echo. * Random Element [!_Rnd#!] of %%~A Pseudo Array = "%%_Arr.%%~A.!_Rnd#!%%"
)
ENDLOCAL
GOTO :EOF
:Get-Rnd
SET /A "_RandMax=(32767 - ( ( ( 32767 %% %~1 ) + 1 ) %% %~1) )", "_Rnd#=!Random!"
IF /I !_Rnd#! GTR !_RandMax! ( GOTO :Get_Rnd# )
SET /A "_Rnd#%%=%~1"
GOTO :EOF
结果示例:
Results:
Names 7 to 9, Plus 5 - Psuedo Randomly Selected
* Element [7] of Names Pseudo Array = "Name 7"
* Element [8] of Names Pseudo Array = "Name 8"
* Element [9] of Names Pseudo Array = "Manual Name 1"
* Random Element [5] of Names Pseudo Array = "Name 5"
Songs 7 to 9, Plus 5 - Psuedo Randomly Selected
* Element [7] of Songs Pseudo Array = "One Angry Dwarf and 200 Solumn Faces"
* Element [8] of Songs Pseudo Array = "Live and Let Die"
* Element [9] of Songs Pseudo Array = "Baby Shark"
* Random Element [5] of Songs Pseudo Array = "The Sound of Silence"
States 7 to 9, Plus 9 - Psuedo Randomly Selected
* Element [7] of States Pseudo Array = "CT"
* Element [8] of States Pseudo Array = "DE"
* Element [9] of States Pseudo Array = "FL"
* Random Element [9] of States Pseudo Array = "FL"
WinDir 7 to 9, Plus 26 - Psuedo Randomly Selected
* Element [7] of WinDir Pseudo Array = "assembly"
* Element [8] of WinDir Pseudo Array = "AUInstallAgent"
* Element [9] of WinDir Pseudo Array = "Boot"
* Random Element [26] of WinDir Pseudo Array = "Fonts"
最初,我会做一些类似于Aacini的事情,即手动地使用带有增量计数器的简单的变量行,或者通过从变量快速列表中进行的简单循环来分配它们。
这对于小型二维阵列很好。
但是,我发现它对于长数据数组很痛苦,尤其是当我需要多值内容时。
更不用说什么时候我需要动态地匹配和填充那些多维数组中的内容了,在那里简单的用法就崩溃了。
我发现当您最终需要全面更新或添加功能所需的多种信息时,这变得很困难。
由于这样的数组本质上是您需要导出为变量的子字符串列表,并且添加或更改其顺序意味着更改代码。
例如,您需要登录多个FTP服务器,从某些路径中删除X天之前的文件。
最初,您可能会创建一些简单的子字符串数组,如下所示:
Site.##=[Array (String)] [Array (String)] @(
IP=[SubSting],
Username=[SubString],
Password[SubString])
或如本示例代码所示。
(
SETOCAL
ECHO OFF
REM Manage Sites:
SET "Sites=13"
SET "MaxAge=28"
SET "Site.1="[IP]" "[User Name]" "[Password]" "[Path]""
SET "Site.2="[IP]" "[User Name]" "[Password]" "[Path]""
SET "Site.3="[IP]" "[User Name]" "[Password]" "[Path]""
REM ...
SET "Site.11="[IP]" "[User Name]" "[Password]" "[Path]""
SET "Site.12="[IP]" "[User Name]" "[Password]" "[Path]""
SET "Site.13="[IP]" "[User Name]" "[Password]" "[Path]""
)
FOR /L %%L IN (1,1,%Sites%) DO (
FOR /F "Tokens=*" %%A IN ('CALL ECHO %%Site.%%L%%') DO (
Echo. Pulled this example from a more complex example of my actual code, so the example variables may not need this loop, but it won't hurt to have if they don't need the extra expansion.
Call :Log
CALL :DeleteFTP %%~A
)
)
GOTO :EOF
:DeleteFTP
REM Simple ftp command for cygwin to delete the files found older than X days.
SET "FTPCMD="%~dp0lftp" %~1 -u %~2,%~3 -e "rm -rf %~4%MaxAge% "
FOR /F "Tokens=*" %%F IN ('"%FTPCMD% 2^>^&1"') DO @(
ECHO.%%~F
)
GOTO :EOF
现在,在13个站点中,这还不是很糟糕,我相信您是在说。对?您可以只在最后添加一个,然后放入信息并完成。
然后,您需要在其中添加要报告的站点的名称,以便在第5位的每个字符串中添加另一个术语,从而不必更改功能。
::...
SET "Site.1="[IP]" "[User Name]" "[Password]" "[Path]" "[Site Name]""
::...
然后,您意识到需要按其站点名称(或IP,但它们的名称对于大多数人来说更容易记住,并且您需要让其他人看一下)保持它们的顺序,因此您可以更改其顺序所有13个点,扩展变量的调用以及函数。
::...
SET "Site.1="[Site Name]" "[IP]" "[User Name]" "[Password]" "[Path]""
::...
FOR /F "Tokens=*" %%A IN ('CALL ECHO %%Site.%%L%%')
::...
SET "FTPCMD="%~dp0lftp" %~2 -u %~3,%~4 -e "rm -rf %~5%MaxAge% "
::...
然后它只会变得越来越糟:
您必须在同一站点上使用不同的用户检查的目录数量开始增加。
您意识到每个站点需要不同的保留时间,以后每个目录需要有不同的保留时间。
您最终拥有其中的30、40、50,通过查看长字符串的末尾并复制它们等等,很难记住是哪一个。
您停止添加更多路径,但是有时您必须删除旧路径,否则当旧路径消失时会引起问题,并且如果您忘记更新站点总数,则可能会错过在某些列表上运行脚本的列表。
当添加或删除目录时,您必须在每个站点上添加/删除目录,这使得使用顺序更加困难,并且由于站点不容易识别,因此更容易错过站点。
只是,这很痛苦,而且甚至在您需要动态对象集时也是如此,这全是手动的。
所以,你可以做什么?好吧,这是我所做的:
我最终诉诸于在需要的cmd脚本中实现某种穷人结构或字符串对象数组。
IE的结构将是一个“站点对象”,它将具有多个属性,这些属性可能是具有子属性本身的对象。由于CMD实际上不是面向对象的,因此有点像数组一样。
由于我开始的示例最终是我尝试的第一个地方,因此您可以看到我将定义的中间汞齐步骤,如下所示:
eg: Site.[ID].[Object Property]=[Value, or array of values]
Site
.ID=[int]
.Name=[string]
.Path=[String]
.MaxAge=[Int]
.Details=[Array (String)] @(
IP=[SubSting],
Username=[SubString],
Password[SubString])
为了解决需要即时对数据集进行重新排序的问题,我考虑过使用一种我喜欢的链接列表形式,但是由于我想轻松地将项目添加到每个网站分组中,同时保留我决定的网站之间的顺序简单的方法。
这是此使用步骤的另一个代码示例:
@(
SETLOCAL ENABLEDELAYEDEXPANSION
ECHO OFF
SET "_SiteCount=0"
SET "_SiteID=0"
SET /A "_SiteID= !_SiteID! + 1"
SET "Site.!_SiteID!.MaxAge=Day5Ago"
SET "Site.!_SiteID!.Name=[SITE NAME HEADER FOR EMAIL]"
SET "Site.!_SiteID!.Detail="[IP]" "[UserName]" "[Password]" "[Path]""
REM ...
SET /A "_SiteID= !_SiteID! + 1"
SET "Site.!_SiteID!.MaxAge=Day15Ago"
SET "Site.!_SiteID!.Name=[SITE NAME HEADER FOR EMAIL]"
SET "Site.!_SiteID!.Detail="[IP]" "[UserName]" "[Password]" "[Path]""
)
CALL :Main
(
ENDLOCAL
Exit /b %eLvl%
)
:Main
REM In some forms of these the order isn't meaningful, but in others you need to follows the order and so we just count he number of site objects by counting one of their properties.
FOR /F %%A IN ('SET ^| FIND /I "Site." ^| FIND /I ".Name="') DO ( CALL SET /A "_SiteCount+=1" )
FOR /L %%L IN (1,1,34) DO (
CALL :PSGetDate_DaysAgo %%L
)
FOR /L %%L IN (1,1,%_SiteCount%) DO (
SET "Site.%%L.Create=NONE"
)
FOR /L %%L IN (1,1,%_SiteCount%) DO (
FOR /F "Tokens=*" %%A IN ('CALL ECHO ""%%Site.%%L.Name%%" %%Site.%%L.Detail%% "Site.%%L" "%%%%Site.%%L.MaxAge%%%%""') DO (
CALL ECHO CALL :DeleteFTP %%~A
CALL :DeleteFTP %%~A
)
)
CALL :SendMail "%EMLog%" "%_EMSubject%"
GOTO :EOF
:DeleteFTP
REM ECHO.IF "%~7" EQU "%skip%" (
IF "%~7" EQU "%skip%" (
GOTO :EOF
)
SET "FTPCMD="%~dp0lftp" %~2 -u %~3,%~4 -e "rm -rf %~5%~7 "
SET "FTPCMD=%FTPCMD%; bye""
FOR /F "Tokens=*" %%F IN ('"%FTPCMD% 2^>^&1"') DO @(
ECHO."%%F"
ECHO."%%~F"
REM CALL :Output "%Temp%\%~2_%~7.log" "%%F"
%OP% "%Temp%\%~2_%~7.log"
SET "FTPOut=%%~F"
)
GOTO :EOF
如您所见,这些结构在需要手动应用并按特定顺序显示数据的分支叉数据集的情况下非常有效。
虽然,为了确保今天的正常运行,我通常将结构的基础称为脚本的名称,因为我发现它更有用,并且可以根据需要使用或不使用有序数组。
SET "_GUID=^%Time^%_^%Random:~-1^%^%Random:~-1^%^%Random:~-1^%^%Random:~-1^%^%Random:~-1^%^%Random:~-1^%^%Random:~-1^%^%Random:~-1^%^%Random:~-1^%"
eg: %~n0.[ObjectName].[Object Property].[Object Sub Property]=[Value, or array of values]
[Script Name]
.[Object Name](May Hold Count of Names)=[int]
.Name=[string]
.Paths(May Hold Count of IDs)=[INT]
.GUID=%_GUID%
.Path=String
.MaxAge=[Int]
.Details=[Array (String)] @(
IP=[SubSting],
Username=[SubString],
Password[SubString])
但是,您可能需要在何处收集大量动态生成的数据,然后将其分组为预制类别,然后将其混合起来以进行报告。
在这里,这些同样也很有用,您可以在代码中即时构建它们,并根据需要添加更多属性。
在与FTP删除类似的脚本中,我们需要检查多个目录的大小,我要花很多时间来简化一下,仅查看一项检查:
@(
SETLOCAL ENABLEDELAYEDEXPANSION
ECHO OFF
SET /A "_SiteID= !_SiteID! + 1"
SET "SiteName=SiteA"
SET "%~n0.!SiteName!=%%_SiteID%%
SET "%~n0.!SiteName!.SiteID=!_SiteID!
SET "%~n0.!SiteName!.Paths="PathA" "PathB" "PathC" "PathD" "PathE""
)
CALL :CheckFTP [FTP Login variables from source object including Site ID]
:CheckFTP
REM Not necessary to assign Variables, doing this for exposition only:
CALL SET "TempSiteName=%~6"
CALL SET "TempPaths=%%%~n0.%~1.Paths%%"
REM Clear the site Temp KB variables
FOR \F "Tokens=2* Delims== " %%H IN (%TempPaths% "Total" "Temp") DO (
CALL SET /A "%%%~n0.%~1.Paths.%%~H.KB=0"
)
FOR %%J IN (%TempPaths%) DO (
FOR /F "Tokens=1-2" %%F IN ('[FTP Command using source object options]') DO @(
CALL :SumSite "%~6" "%%~F" "%%~G"
FOR /F "Tokens=1,2,* delims=/" %%f IN ("%%~G") DO (
CALL :ConvertFolder "%~6" "%%~F" "%%~g" "%%~h" "%~6_%%~g_%%~h"
)
)
)
FOR /F "Tokens=3,4,7 Delims==_." %%g IN ('SET ^| FIND /I "%~6_" ^| FIND /I ".KB" ^| FIND /I /V "_."') DO (
CALL :WriteFolder "%%g/%%~h" "%TmpFile%" "%~6_%%~g_%%~h"
REM echo.CALL :WriteFolder "%%g/%%~h" "%TmpFile%" "%~6_%%~g_%%~h"
)
CALL :ConvertSite "%~1"
CALL :WriteTotalFolder "%~7" "%TmpFile%" "%~6"
CALL :SendMail "%TmpFile%" "Backup_%~1"
GOTO :EOF
:SumSite
CALL SET "TSumPaths=%%%~n0.%~1.Paths%% "Total""
FOR %%H IN (%TSumPaths%) DO (
CALL SET /A "%~n0.%~1.Paths.%%~H.KB=%%%~n0.%~1.Paths.%%~H.KB%%+%~2"
)
:SumSite
CALL SET "TSumPaths=%%%~n0.%~1.Paths%% "Total""
FOR %%H IN (%TSumPaths%) DO (
CALL SET /A "%~n0.%~1.Paths.%%~H.KB=%%%~n0.%~1.Paths.%%~H.KB%%+%~2"
)
GOTO :EOF
:ConvertFolder
REM Convert's Folder values to MB and GB
SET /A "%~1.Temp.KB=%~2"
CALL SET /A "%~1.Temp.MB=%%%~1.Temp.KB%%/1024"
CALL SET /A "%~1.Temp.GB=(%%%~1.Temp.KB%%/1024)/1024"
CALL SET /A "%~5.Temp.KB=%%%~5.Temp.KB%%+%~2"
CALL SET /A "%~5.Temp.MB=%%%~5.Temp.KB%%/1024"
CALL SET /A "%~5.Temp.GB=(%%%~5.Temp.KB%%/1024)/1024"
GOTO :EOF
:WriteFolder
CALL :PickGMKBytes "%~1" "%~2" "G" "M" "K" "%%%~3.Temp.GB%%" "%%%~3.Temp.MB%%" "%%%~3.Temp.KB%%"
GOTO :EOF
:PickGMKBytes
IF /I "%~6" NEQ "" (
IF /I "%~6"=="0" (
CALL :PickGMKBytes "%~1" "%~2" "%~4" "%~5" "%~6" "%~7" "%~8"
) ELSE (
CALL :Output "%~2" "%~6%~3 %~1"
)
) ELSE (
CALL :Output "%~2" "0B %~1"
)
GOTO :EOF
:ConvertSite
CALL SET "TempPaths=%%%~n0.%~1.Paths%%"
FOR %%V IN (%TempPaths% "Total") DO (
CALL SET /A "%~1.%%~V.MB=%%%~1.%%~V.KB%%/1024"
CALL SET /A "%~1.%%~V.GB=(%%%~1.%%~V.KB%%/1024)/1024"
)
GOTO :EOF
公平地讲,此脚本示例可能无法非常清楚地显示正在发生的事情,因此我不得不即时进行更改以修复新的对象样式,但实际上:它创建连接对象,然后动态扩展它们以包括sub文件夹,并维护每个子文件夹和站点的运行总计(以KB,MB和GB为单位),并动态汇总给定文件夹的所有目录等后,报告要报告的值。
虽然我不得不对其进行一些编辑,因为这也是它们的较早版本,但我认为这是最能体现其优势的实例之一。如果我在其他脚本之一中找到了更好的示例,则也可以在那里进行更新。
@ECHO OFF
Set "UseErr=Echo/&Echo/Usage Error - Ensure command extensions and Delayed Expansion are enabled with: &Echo/Setlocal EnableExtensions EnableDelayedExpansion&Echo/ or from the command line:&Echo/CMD /V:On /K&Exit /B 1"
If Not "!Comspec!"=="%Comspec%" (%UseErr%)
(Set "GRPNm="&Set "TAB= "&Set "S_Offset="&Set "mode="&Set "#STDOut="&Set "nGRPNm="&Set "#Order="&Set "#Help="&Set "Inset="&Set "Usage=Echo/###&Exit /B 1") > Nul 2> Nul
(Set "SwParam="&Set "SwFParam="&Set "#ORP#=0"&Set "#FP#=0"&Set "Inset="&Set "#STDOut=0"&Set "GRPNm="&Set "!GRPNm!="&Set "SubEl="&Set "FlNm=%~n0"& Set "Mode="&Set "FindV=") > Nul 2> Nul
If "%~1"=="" (
Echo/&Echo/Modes:&Echo/ [Def]!TAB!!TAB!!TAB!Define, modify or clear an array.
Echo/ [Def]!TAB!!TAB!!TAB!Switches:!TAB![/A:Groupname] [/F:Filepath.ext] [/D] [/O:Index#Arg] [/E:Element Sub value] [[element0] ~ [element#]]
Echo/ [Sort-int]!TAB!!TAB!Sorts array by lowest or highest value using /L or /H switches
Echo/ [Sort-int]!TAB!!TAB!Switches:!TAB![/A:Groupname] [/N:New Groupname] [/L^|/H] [/D]
Echo/ [Sort-str]!TAB!!TAB!Sorts an array or text files string values using alphanumerical order of sort: [0-9][a-z]
Echo/ [Sort-str]!TAB!!TAB!Switches:!TAB![/A:Groupname] [/F:Filepath.ext] [/D]
Echo/ [Find] !TAB!!TAB!Searches an array for the string value supplied.
Echo/ [Find] [searchstring]!TAB!Switches: [/A:Groupname]&Echo/
%Usage:###=/M:Mode required&Echo/[Def][Sort-int^|str][Find-Value]%
) Else Call :GetArgs %*
If Errorlevel 1 Exit /B 1
If "!Mode!"=="" (%Usage:###=/M:Mode required&Echo/[Def][Sort-int^|str][Find-Value]%)
Call :!Mode! %* 2> Nul || (%Usage:###=Invalid Mode or switch error for /M:!Mode!&Echo/[Def][Sort-int^|str][Find-Value]%)
Exit /B 0
:str
Set "Usage=Echo/###&Echo/Call !FlNm! ["/F:filepath.ext" ^| "/A:Array Group Name"] & Exit /B 1"
Set "#!GRPNm!=0"
If "!#FP#!"=="1" (
(For /F "UseBackQ Delims=" %%G in (`Type "!FilePath!" ^| Sort`)Do (
For %%x in ("!GRPNm![!#%GRPNm%!]") Do (
Setlocal DisableDelayedExpansion
Endlocal & Set "%%~x=%%~G"
If "!#STDOut!"=="1" Echo/%%~x=%%~G
)
Set /A "#!GRPNm!+=1"
)) 2> Nul || (%Usage:###:=Echo/Invalid Filepath:"!FilePath!"%)
Exit /B 0
)
If Not "!#FP#!"=="1" (For /F "Tokens=1,2 Delims==" %%G in ('Set !GRPNm![')Do Echo/%%H)>"%TEMP%\__Sort.txt"
(For /F "UseBackQ Delims=" %%G in (`Type "%TEMP%\__Sort.txt" ^| Sort`)Do (
For %%x in ("!GRPNm![!#%GRPNm%!]") Do (
Setlocal DisableDelayedExpansion
Endlocal & Set "%%~x=%%~G"
If "!#STDOut!"=="1" Echo/%%~x=%%~G
)
Set /A "#!GRPNm!+=1"
)
)
Del /Q "%TEMP%\__Sort.txt"
Exit /B 0
:Find
Set "Usage=Echo/###&Echo/Call !FlNm! [/M:Find-Searchstring] [/A:Group Name]&Exit /B 1"
If "!FindV!"=="" (%Usage:###=/M:Find-Value Required%)
(For /F "Tokens=1,2 Delims==" %%i in ('Set !GRPNm![') Do Echo/"%%j"|"%__AppDir__%findstr.exe"/LIC:"!FindV!" > Nul 2> Nul && (Echo/!FindV! found:&Echo/%%~i=%%~j))
Exit /B 0
:Int
Set "Usage=Echo/###&Echo/Call !FlNm! [/M:Sort-Int] [/A:Group Name] [/N:New Group Name] [Sort-Int] [/H^|/L]&Echo/Call %~n0 [/M:Sort-Int] [/A:Groupname] [Sort-Int] [/H^|/L]&Exit /B 1"
If "!#Help!"=="1" (%Usage:###=/M:Sort-Int Usage:%)
If "!nGRPNm!"=="" Set "nGRPNm=!GRPNm!"
If Not "%#Order%"=="" (Call :Sort%#Order% !nGRPNm! #!nGRPNm! !Inset!) Else (%Usage:###=Sort Order Required /H or /L%)
Exit /B 0
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: Subroutines for Population of Arrays with numeric values in sorted order.
:sortL <Element_VarName> <Element_Index_VarName> <Variable Names containing the values to be Sorted and Populated to the Array>
Set "%2=0"
FOR %%P In (%*) DO If Not "%%P"=="%1" If Not "%%P"=="%2" If Not "%%P"=="" (
Set "%1[!%2!]=!%%P!"
Set /A "%2+=1"
)
For /L %%a In (1,1,!%2!)Do (
Set /A "S_Offset=%%a - 1"
For /L %%b IN (0,1,%%a)Do (
If not %%b==%%a For %%c in (!S_Offset!)Do (
IF !%1[%%c]! LEQ !%1[%%b]! (
Set "tmpV=!%1[%%c]!"
Set "%1[%%c]=!%1[%%b]!"
Set "%1[%%b]=!tmpV!"
))))
Set /A %2-=1
If "!#STDOut!"=="1" For /L %%G in (0 1 !%2!)Do Echo/%1[%%G]=!%1[%%G]!
Exit /B 0
:sortH <Element_VarName> <Element_Index_VarName> <Variable Names containing the values to be Sorted and Populated to the Array>
Set "%2=0"
FOR %%P In (%*) DO If Not "%%~P"=="%~1" If Not "%%~P"=="%2" If Not "%%P"=="" (
Set "%1[!%2!]=!%%~P!"
Set /A "%2+=1"
)
For /L %%a In (1,1,!%2!)Do (
Set /A "S_Offset=%%a - 1"
For /L %%b IN (0,1,%%a)Do (
If not %%b==%%a For %%c in (!S_Offset!)Do (
If Not !%1[%%c]! LSS !%1[%%b]! (
Set "tmpV=!%1[%%c]!"
Set "%1[%%c]=!%1[%%b]!"
Set "%1[%%b]=!tmpV!"
))))
Set /A %2-=1
If "!#STDOut!"=="1" For /L %%G in (0 1 !%2!)Do Echo/%1[%%G]=!%1[%%G]!
Exit /B 0
:Def
Set "Usage=Echo/###&Echo/Call !FlNm! [/M:Def] [/A:Groupname] ["element0" ~ "element#"] [/F:Filepath.ext] [/E:"Element sub value"]&Echo/ - Assign each line in the given filepath plus element parameters to the Array&Echo/Call %~n0 [/M:Def] [/A:Groupname] REM : Clears the Array for the given Group Name&Echo/Call %~n0 [/M:Def] [/A:Groupname] [element] [element] [/O:Index#Arg] REM : Overides Elements from the index supplied&Exit /B 0"
If "!#ORP#!"=="1" Echo/!SwParam!|"%__AppDir__%findstr.exe" /RX [0-9]* > Nul 2> Nul
If not "!SwParam!"=="" If Errorlevel 1 (%Usage:###=O:!SwParam! #Arg invalid. Only Integers accepted.%)
If "!GRPNm!"=="" (%Usage:###=/A:Groupname Required%)
If "!#ORP#!"=="1" Set "#!GRPNm!=0"
If "!#%GRPNm%!"=="" Set "#!GRPNm!=0"
If "%#FP#%"=="1" (
If exist "!FilePath!" (
For /F "Delims=" %%G in (!FilePath!)Do If Not "%%~G"=="" (
For %%x in ("!GRPNm![!#%GRPNm%!]")Do (
Setlocal DisableDelayedExpansion
If "%#STDOut%"=="1" Echo/%%~x=%%~G
Endlocal & Set "%%~x=%%G"
)
Set /A "#!GRPNm!+=1" > Nul
)
) Else (%Usage:###=/F:!FilePath! Invalid path%)
)
If not "!Inset!"=="" (
For %%G in (!Inset!)Do (
For %%x in ("%GRPNm%[!#%GRPNm%!]")Do (
Setlocal DisableDelayedExpansion
If "%#STDOut%"=="1" Echo/%%~x=%%~G
Endlocal & Set "%%~x=%%~G"
)
If Not "!SubEL!"=="" Set "%%~G=!SubEl!"
Set /A "#!GRPNm!+=1" > Nul
)
) Else (
If Not "%#FP#%"=="1" (
For /F "Tokens=1,2 Delims==" %%I in ('Set %GRPNm%')Do Set "%%~I=" > Nul 2> Nul
Set "#!GRPNm!=" > Nul 2> Nul
)
)
Exit /B 0
:GetArgs
If Not "!#Help!"=="1" If "%~1" == "" (
If /I "!Mode!"=="int" If "!GRPNm!"=="" (Echo/Call %~n0 [/M:Sort-int] [/A:GroupName] [/H^|/L] [/D]&%Usage:###=/A:Groupname Required%)Else If /I "!Mode!"=="int" (For /F "Tokens=1,2 Delims==" %%G in ('Set !GRPNm![')Do Set "Inset=!Inset! %%G") > Nul 2> Nul || (%Usage:###=Usage Error - /A:!GRPNm! is not defined%)
If /I "!Mode!"=="str" If "!GRPNm!"=="" (Echo/Call %~n0 [/M:Sort-str] [/A:GroupName] [/N:New Groupname] [/F:Filepath.ext] [/D]&%Usage:###=/A:Groupname Required%)Else If /I "!Mode!"=="str" (For /F "Tokens=1,2 Delims==" %%G in ('Set !GRPNm![')Do Set "Inset=!Inset! %%G") > Nul 2> Nul || (%Usage:###=Usage Error - /A:!GRPNm! is not defined%)
Exit /B 0
) Else If "%~1" == "" Exit /B 0
Set "Param=%~1"
Echo/"!Param!"|"%__AppDir__%findstr.exe" /LIC:"Find-" > Nul 2> Nul && ((Set "FindV=!Param:/M:Find-=!"&Set "Mode=Find")&Shift&Goto :GetArgs)
Echo/"!Param!"|"%__AppDir__%findstr.exe" /LIC:"/M:" > Nul 2> Nul && (
Set "MODE=!Param:*/M:=!"& Echo/"!Mode!"|"%__AppDir__%findstr.exe" /LIC:"Sort-" > Nul 2> Nul && (Set "Mode=!Mode:*Sort-=!")
If "!Param:*/M:=!"=="" (
Echo/&Echo/Modes:&Echo/ [Def]!TAB!!TAB!Define, modify or clear an array.
Echo/ [Sort-int]!TAB!Sorts array by lowest or highest value using /L or /H switches
Echo/ [Sort-str]!TAB!Sorts an array or text files string values using alphanumerical order of sort: [0-9][a-z]
Echo/ [Find:Value]!TAB!Searches an array for the string value supplied.&Echo/
%Usage:###=/M:Mode required&Echo/[Def][Sort-int^|str][Find-Value]%
)
Shift&Goto :GetArgs
)
Echo/"%~1"|"%__AppDir__%findstr.exe" /LIC:"/H" > Nul 2> Nul && (Set "#Order=H"&Shift&Goto :GetArgs)
Echo/"%~1"|"%__AppDir__%findstr.exe" /LIC:"/L" > Nul 2> Nul && (Set "#Order=L"&Shift&Goto :GetArgs)
Echo/"%~1"|"%__AppDir__%findstr.exe" /LIC:"/D" > Nul 2> Nul && (Set "#STDOut=1"&Shift&Goto :GetArgs)
Echo/"%~1"|"%__AppDir__%findstr.exe" /LIC:"/F:" > Nul 2> Nul && ((If Not "!Param:/F:=!"=="" (Set "#FP#=1"&Set "FilePath=!Param:/F:=!")Else %Usage:###=/F:Filepath.ext not Supplied%)&Shift&Goto :GetArgs)
Echo/"%~1"|"%__AppDir__%findstr.exe" /LIC:"/N:" > Nul 2> Nul && (Set "nGRPNm=!Param:*/N:=!"&(If "!Param:*/N:=!"=="" %Usage:###=/N:New Group Name required%)&Shift&Goto :GetArgs)
Echo/"%~1"|"%__AppDir__%findstr.exe" /LIC:"/A:" > Nul 2> Nul && (Set "GRPNm=!Param:*/A:=!"&(If "!Param:*/A:=!"=="" %Usage:###=/A:Group Name required%)&Shift&Goto :GetArgs)
Echo/"%~1"|"%__AppDir__%findstr.exe" /LIC:"/O:" > Nul 2> Nul && (Set "SwParam=!Param:*/O:=!"&(If Not "!Param:/O:=!"=="" (Set "#ORP#=1")Else %Usage:###=/O:#Arg not Supplied%)&Shift&Goto :GetArgs)
Echo/"%~1"|"%__AppDir__%findstr.exe" /LIC:"/E:" > Nul 2> Nul && (Set "SubEl=!Param:*/E:=!"&(If "!Param:/S:=!"=="" %Usage:###=/E:Sub Element not Supplied%)&Shift&Goto :GetArgs)
Set Inset=!Inset! %1
Shift&Goto :GetArgs
Def]定义,修改或清除数组。Def]切换:[ /A:Groupname] [ /F:Filepath.ext] [ /D] [ /O:Index#Arg] [ /E:Element Sub value] "element0"〜"element#"Sort-int]使用/L或按最小值或最大值对数组排序/H开关Sort-int]开关:/A:Groupname] [ /N:New Groupname] [ /L| /H] [ /D]Sort-str]Sort-str]开关:/A:Groupname] [ /F:Filepath.ext] [ /D]Find-searchstring]Find-searchstring]开关:[ /A:Groupname]是的,据我所知,Batch是Turing的完整版(如果您忽略了“无限”的功能,例如无限的内存和计算时间,则可能会说Batch在理论上只是“与Turing等效”)。
所有基本布尔和算术运算符以及循环(for)和分支(if)都有。也有一个goto其允许建模循环(功能while/ do while/ for)和sub routines。可以嵌套块。Variables可以命名,存储,删除/清除,显示/写入文件。甲halt条件可以与达到exit(或GOTO EOF)。
附带说明:可以从批处理程序内部写入批处理文件,将其写入磁盘并运行(允许自我修改/自定义/子例程/状态保存和恢复)。
但是,没有无限的内存存储空间。在计算中只能使用32位算术。显然,运行批处理文件的计算机还具有硬件和物理限制(只有有限的时间,速度或空间)。
应该注意的是,您提到的所有“高级”概念都不是“批处理编程语言”的一部分。没有集成类,对象,记录/结构,数组,链表,堆栈,队列等的概念。也没有提供任何缺省算法,如排序等(可能除了如果sort或findStr,more等用管道考虑)。使用%RANDOM%变量进行随机化也是非常基本的。
如果需要这些概念,则需要自己使用上面提到的给定的基本语言元素对它们进行建模(或为此使用一些库/第三方批处理文件)。
当然可以call不仅批处理文件,而且还包括计算机上的任何补充程序,然后返回批处理执行(通过文件,标准I / O流或退出/错误级别代码进行通信)。这些程序可以用高级语言编写,以更方便的方式提供这些内容。
以我的观点,Bash(Linux)和Powershell(Windows / Linux)在这些领域中要先进得多。
@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%]!