📜 ⬆️ ⬇️

Working with arrays in bat

After reading the post Your sapper on his batch file and running through the code, I came across a comment that there are no arrays in the batch file (by the way, the latest version of the Sapper, which is discussed in that post, does not have this comment). So, if in a batch file it is necessary to use a certain set of values, then it is logical to declare such number of variables that you need and work with them. Actually this scenario helps to solve this problem easier. Here are some examples:

 echo Create array A:
 call: array new A "'one', 'two', 'three', 'foo', 'bar'"
 echo Getting the third element in result:
 call: array get A 3 result
 echo% result%
 echo Null element change
 call: array set A 0 "first element"


Principle


Arrays are handled by calling calls call :array and passing the appropriate parameters. The first parameter is the action, and the second is the array name. These two may be followed by optional parameters as well as optional ones. Each array is a set of variables of the form array_[ ]_[ ] and one variable containing the size — array_[ ]_count . It is assumed that these variables are not manually changed.

Creating arrays


There are several methods for creating arrays. The main ones are create , new and load .
The create method creates an array of the specified size. You can also set initial values ​​that are zero by default. And yet, I must say that the values ​​can not be empty, this is a feature of the set command.
')
rem call :array call :array create _ [=0] [ =0]

rem
call :array create myArray

rem , 5. - 0
call :array create myArray 5

rem , 5 "my value"
rem
call :array create myArray 5 "my value"


But it is much more convenient to create an array immediately with the assignment of values. To do this, use the new command:

rem call :array new _ "1, 2, '' ..."

rem A 90, 56, ' '
call :array new A "90 56 ' '"


You can load values ​​from an external file. I would like to note that the source file must be encoded in 1251 and the current code page does not affect this:

rem call :array load _ _

rem records.txt Table. - .
call :array load Table records.txt


Access to items



Access to each element is possible by index. I must say a few words about the procedures that return value. Because in batch files there is no possibility to return the value from the procedure (we will call this what is called via call), then you have to make a feint with your ears: all procedures that are expected to produce a result write it to the variable _l (ale is small, sort of like from the word last. Although then I began to lean toward the fact that result is more logical). The name of a variable can, as a rule, be redefined by passing its name to the last parameter.

rem call :array get _ [index=0] [__=_l]

rem myArray. _l
call :array get myArray
echo - %_l%

rem myArray ok
call :array get myArray -2 ok
echo : %ok%


Debugging often requires fast output. This can help echo (alias to get + echo) and dump (print array).
rem myArray
call :array echo myArray -1

rem
call :array dump myArray

The printout looks like this:
array[4]: myArray
[0]
[1]
[2] 3
[3]


Displaying items in a list using list allows you to save it to a file. Unfortunately, I could not redirect it to another team. For example call :array list myArray | sort call :array list myArray | sort results in the error "Invalid attempt to jump to the label of a batch file from outside this file."
call :array list myArray > output.txt

To get the number of elements, use the count command (in fact, it simply reads it from the variable array_[ ]_count , but with additional checks for existence and so on:
call :array count myArray len
echo %len% .


The find returns the index of the first element found, or -1 if there are no matches. Here are the so-called flags. These are parameters that may or may not be. They usually come last, but sometimes after them you can specify the name of the variable for the result, and the question may arise how to be then. In this case, if the flag is not needed, and you need to set a variable, simply specify any other value in the position of the moisture, for example, #, or minus. Well, in examples I will show.

rem call :array find _ _ N [__=_l]
rem N - I. , N .
rem sebastNum , .
call :array find myArr " " N sebastNum

rem :
call :array find myArr " " I sebastNum

rem _l:
call :array find myArr " "


Array Manipulations



So far I have implemented setting the value of an element by index, deleting elements, copying arrays, deleting arrays, adding elements.

And I must say about the sets. Some procedures can pass sets as parameters. These sets are then passed to the for command for processing, so they should be written as this for wants. And it is not demanding: the elements of a set are separated by a comma (,) or a space (), and string elements must be enclosed in quotes. But since the parameters themselves are also enclosed in double quotes, then the sets must be single ('). See example add.

rem
rem call :array set _
call :array set myArray 5 ' '

rem
rem call :array copy _ _
call :array copy myArray finalArray

rem
rem call :array add _
rem call :array add myArray 2012

rem . , , , ! -
rem call :add _ !
call :array add myArray "' ' 120 454.34 'sd'" !
rem expand "!"
call :array expand myArray "' ' 120 454.34 'sd'"

rem
rem call :array del _ [_| = ]

rem ( del) , -
rem myArr 9
call :array del myArr 9

rem ,
rem myArr 4, 6 8
call :array del myArr "4,6,8"

rem ,
call :array del myArr


Additional features



This is in my opinion the most interesting operations. They could be attributed to the manipulations, but I decided to isolate them separately.

Saving to a file in cp1251 encoding



Saving to a file can be implemented, as mentioned above, using the list output redirection. But if you need to save to the file in cp1251 encoding, then it is better to use the save command:
rem call :array save _ _

call :array save results .txt


Array sorting



Executed by the sort command. It was possible to implement sorting with the usual bubble, but I decided to use the help of the sort command. But in this approach there are a number of minuses: two files are created in the temporary directory (the dropped array and sorted, which are then, it’s true, are still deleted) and the numbers are sorted as strings. There are two advantages to truth too: as it seems to me, it’s still faster, although I didn’t pursue speed (and this can be seen from the del operation with a set of indices), and simplicity, and this finally caused me to choose this method.

rem call :array sort _ [R - ]

rem myArray
call :array sort myArray R


Application of the procedure to each element



The each command is used and there are two approaches here. The first is the transfer of the command itself. In this case, you can use the _i_ substitutions for the index of the current element and _val_ for its value. To make the script understand that you are passing a command, specify the last parameter x (x)

call :array new B "1 4 1 6 7 2"
set sum=0
call :array each B "set /a sum+=_val_" x
rem sum ( )


The second approach is to specify the label that will be called for each element: call :__ . If the first method is simple, then this provides more flexibility. For example:

rem
call :array new someArray "1902 2007 2012 1954 1945 1989"

rem
set pos=0
call :array get someArray %pos% val

rem findMax
call :array each someArray findMax

rem
echo %val%. %pos%

goto :eof

:findMax
rem %~1 - ( , ~)~, %2 - .

if %~1 GTR %val% (
set val=%~1
set pos=%2
)

goto :eof


Auxiliary procedures



To implement some operations, some separate procedures are used (they are called not via: array, this is what is meant). They may also seem interesting:


Download



You can view the code on Google Docs or pastebin.com .

Thanks, now I can do something really useful.

Source: https://habr.com/ru/post/75951/


All Articles