New Title

New Paragraph
New Paragraph
New Paragraph

New Title


Follow us

Create & Execute Windows Batch Files

This page contains code "snippets" for the YouTube video of the same name.

Creating & Executing Windows Command Files - Intro Part 1

Show sample .bat file
SET/A b = 6
ECHO %b%
SET/A b = %b% / 3
ECHO b=%b%
SET/A c = 8
ECHO c=%c%
SET/A d=%c% + %b%
ECHO d= %d%
IF %b% LSS %c% ECHO b is less than c
IF %b% GTR %c% ECHO greater than or equal
IF %b% NEQ %c% (
ECHO 1
ECHO 2
)
PAUSE

These videos show how to prepare and execute windows command files. Command files are also called Batch files, and have file extension .bat. Instructions in batch files are executed by the windows operating system command interpreter. These videos start with basic definitions and commands, then describe more advanced topics. Executible batch files are provided for each topic described.
Even if you have not done ANY programming before, these
videos will "get you going".

These links are mentioned in the videos. Clickable links are displayed below this video window.
My website: http://webpages.charter.net/User/Tomstda
Webpage containing the script for this video:
http://webpages.charter.net/tomspage/TTNSite/tutscripts.html.
My YouTube channel: https://www.youtube.com/channel/UCL04j8NOAaoZZlZxJBIAZHg
To save shortcuts for the above links on your desktop, you must open the links in the Chrome, Firefox, or Internet Explorer browsers (NOT the Edge browser). Drag the symbol to the left of the URL onto your desktop, then rename it. Here's an example.

Many batch commands CAN be typed and executed one by one in the command prompt window. (demonstrate) Right-click the windows logo, select [command prompt], type each command & press enter. To close the command prompt window click the "x" box, or type "exit"and press return.

These videos won't be using line-by-line command entry. (demo) It's much more useful to create a batch file like this one containing a list of commands. Double-click the file to execute all the commands, using the command-line interpreter.

Before watching the rest of these videos, you should set up several test files.
Start by creating a folder on the desktop or in a folder. If you move it later, put a shortcut on the desktop. (SHOW) If you move a command file later, you may need to change commands using file or folder paths (those will be discussed later). Right-click the desktop, select new folder type the name [batch folder], click elsewhere to save the name. Double-click the folder to open it.
Right-click inside the new folder (or on the desktop, if you prefer), select new, text document. Don't change the name, just double-click the new doc to open it. Click "file", "save as", change "save as type" from text docs to "all files". Type the file name -- we'll use [test batch file.bat], click save. To save time later, create copies of the (empty) batch file: right-click and drag the new .bat file and select copy . You can rename the copies later, as you need them.
If you didn't create "batch folder" on your desktop, you'll need to create a desktop shortcut to the folder. Just right click folder "batch folder", drag to the desktop. When you release the button, shorten the shortcut name to "batch file". If you created "batch folder" on the desktop, you don't need a shortcut.

Also, create a shortcut to my website page "Tutorial Scripts", which lists the scripts for these videos. The clickable link to the website page is below this video window. If it's not visible on your device, pause and copy this URL: http://webpages.charter.net/tomspage/TTNSite/tutscripts.html. Should I ever move my website, you can find it by clickng the link on my YouTube channel banner.

Create & Execute Windows Command Files - Intro Part 2

This video gives suggestions for watching the videos and for debugging your batch files.

(show playlist)
Here is the playlist. The series is under construction. Check back from time to time to see its progress. And here is the website page containing the video scripts for the playlist. As new videos are uploaded to YouTube, their scripts will be added to the webpage.
Here's how I suggest you use the videos. Open the video and the video script webpage from the desktop shortcuts you created while watching the previous video. Arrange the windows so they each take about 1/2 of the desktop, with extra space for the shortcut to your test folder. Pause and replay parts as necessary. When a "snippet" of code is described, pause the video, copy that section from the website script for that video into a .bat file. Execute the batch file, try some variations in it. Clickable links to the YouTube channel page and to the website page are given below this video window.

If you haven't already done so, You should create shortcuts on your desktop.
open each link, and drag a shortcut from your browser to your desktop.
Demo this
Here's how to paste "snippets" from my website to your batch file, open the website page, hilite the lines to copy, press control-c to copy them to the clipboard. Right-click an (empty) .bat file, and select edit. press control-v to paste in the lines.
Script creation and debug tips.
Arrange the desktop so you can see both the open editor window and the batch file icon. Don't close the editor window after making changes-- just click file-save, then double-click the file icon to execute the file.
Many errors will cause the interpreter window to disappear. And the window disappears after the last instruction executes. Insert a PAUSE commands at the end while debugging. If the screen disappears due to an error, insert PAUSE comands until you locate the error. When you execute the file, click any key to advance from one PAUSE to the next.
If you execute the batch file multiple times to debug it, without executing the last (PAUSE) instruction, you'll have to close previous interpreter windows as they stack up.

Creating & Executing Windows Command Files - Basic Commands & Syntax

This video describes basic batch file commands, including the ECHO, SET, IF commands, and arithmetic and comparison operations.

Syntax
Brackets [] surround exact user inputs in my written tutorials -- do not type them in the command files, unless otherwise stated.
The code below illustrates these topics:
Comments: Comments are text lines inserted to explain the code. They are ignored by the command-line interpreter. Comment lines begin with double colons [::], or with [REM].
Case: most of the command syntax is case-insensitive. Either uppercase or lowercase letters can be used, or even mixed. But it's best to adopt a convention (eg. make all keywords and labels caps)
ECHO: The ECHO command writes a line to the command-interpreter window.
PAUSE: The PAUSE command pauses execution until a key is pressed. Without the PAUSE, the command-interpreter window closes after the last command is executed.
example:
:: This comment is the first line in the group
:: By default ECHO is ON
REM This is a rem comment
ECHO This line displays
ECHO off
ECHO Hi, there! I am an apteryx, a wingless bird with hairy feathers!
ECHO on
EcHo The capitalization doesn't matter (most of the time)
PAUSE
Using variables and expressions:
Variable names can contain any characters except [=], but best to avoid [:]. I prefer to just use letters, numbers, and underscores.
SET: The set command initializes variables, sets variables to calculated values.
Arithmetic operations: + - * / %
Comparison operations: EQU NEQ LSS LEQ GTR GEQ
The arithmetic operations can be used with the SET/A command, while the comparison operations are used with the IF command.
IF conditional command
Forms:
IF comparison operation-if-true
IF comparison operation(
multiple lines to execute if true
)
Example:
SET/A b = 6
ECHO %b%
SET/A b = %b% / 3
ECHO b=%b%
SET/A c = 8
ECHO c=%c%
SET/A d=%c% + %b%
ECHO d= %d
IF %b% LSS %c% ECHO b is less than c
IF %b% GTR %c% ECHO greater than or equal
IF %b% NEQ %c% (
ECHO 1
ECHO 2
)
PAUSE

Create & Execute Windows Command Files -
Loops And Branching

This video describes basic FOR loops and features related to branching, such as GOTO commands and labels.

Two forms of FOR are:
FOR variable IN (value1 value2 value3...) DO command
FOR /L variable IN (start,step,end) DO command

FOR variable must be a single letter, and is case sensitive. All uses within the for loop must be the same case, either all caps, or all lower case. In batch files, the variable must be prefixed with [%%].
Example:
FOR %%x IN (1 3 5 7 ) Echo %%x
FOR /L %%x IN (1,2,7) DO ECHO %%x
PAUSE

And this runs with no problems.
However, when you use "ordinary" variables in a loop structure, or in any other command block structure, things can get complicated.

set y=this is y
for %%x in (1 2 3 4) do (
echo %%x
set y=%%x
echo y=%y%
)
pause

Look at the echo of y=%y%
They all show the same value, even though they are preceded by the statement that changes y.
When the batch file processor expands the code, ALL lines of the FOR get expanded before they are executed. Before execution, y="this is y".
So the instruction becomes echo y=this is y for all passes through the loop.
The batch command setlocal enabledelayedexpansion solves this problem. When the command is inserted, the code behaves as it did before. However, if you enclose variables with [!], instead of [%], they won't be expanded until the instruction is executed.


This example shows the modified code.
ECHO.
ECHO.
ECHO.
SETLOCAL enabledelayedexpansion
SET y=this is y
FOR %%x IN (1 2 3 4) DO (
ECHO %%x
SET y=%%x
ECHO y=!y!
)
PAUSE

GOTO and labels. These features allow complex batch files to be created.

Here's an example.
SET y=3
:TESTIT
ECHO Y is now %y%
IF %y% EQU 10 GOTO DONE
:: optional form
:: IF %y% EQU 10 GOTO:EOF
ECHO y not 10
SET/A y=%y%+1
GOTO TESTIT
:DONE
PAUSE

Create & Execute Windows Command Files -
Prompting For User Inputs

This video shows how to prompt for and read user inputs from batch files

This code shows how to prompt the user for keyboard input of text or numbers in a loop, then process the values. All user entries must be ended by pressing ENTER. Both examples exit the loop when the user presses ENTER without typing.

ECHO off
:GETINPUT
SET answer=""
SET/P "answer=Enter today's date, then press enter: "
if %answer%=="" GOTO DONE
:: insert commands to process the date
ECHO You entered "%answer%"
GOTO GETINPUT
:DONE
PAUSE
ECHO.
ECHO.
ECHO off
:GETINPUT1
SET answer=""
SET/P "answer=Enter a number to calculate the square: "
if %answer%=="" GOTO DONE1
SET/A square=%answer% * %answer%
ECHO %answer% squared = %square%
GOTO GETINPUT1
:DONE1
PAUSE

Create & Execute Windows Command Files -
Current Directory

Command files read and write files that are in the same directory as the current directory (or file path), unless a path is specied in the file reference. This video shows how to change the current directory, and how to use file directories in batch code.

show ex
When a batch file is executed directly, the current directory is the directory containing the batch file. But when the same batch file is executed from a shortcut anywhere on my Windows 10 Pro computer, even on an external hard drive, the current directory is C:\Users. To check that on your computer, run any batch file, without turning ECHO off. The current directory is shown whenever a command is ECHOed, or when the CD command is entered, without parameters.
show example
There are MANY ways to display or change the current directory (CD): The following code will show a few of them. I suggest you copy the text from the video script and execute it yourself. Modify the commands to see EXACTLY how they work. Save a shortcut to the video for later reference.
:: Display current directory
CD
::move up one level
CD ..
:Display the directory containing this command file
ECHO %~dp0
::Change the directory
CD C:\Users
::move down one level
CD Tom2
:: change to a different drive
CD /D S:
::or
T:
::change to a different drive and the last directory used on that drive
CD /D C:
::Move down one level
CD Documents
::Change to root (top) directory on different drive
CD /D S:\
::Show the current directory
CD
::Change the current directory to the one containing the batch file
CD /D %~dp0
PAUSE
ECHO.
ECHO.
:: Code to save directories in variables
SET x=%cd%
SET y=%~dp0
ECHO current directory: %x%, Batch File Directory: %y%
PAUSE

Create & Execute Windows Command Files -
Read And Write Files

This video shows how to create, read, and write text files from a command file. The code is self-contained. You should be able to copy it from the script on my webpage, then execute it from any location in your computer. It will create two text files (textout.txt, textout1.txt) in the folder containing the batch file.

This more complicated instructions show how to read text separated by delimiters, save the text "tokens", then modify them in the code. Note: The command line processor is VERY FINICKY about syntax -- you can alter the example to fit your needs, but be VERY CAREFUL with the syntax. Errors may cause the output to disappear, and you need to insert lots of pauses and/or comment lines of code to debug it. You may need to restart your computer after certain errors - some of the error conditions seem to alter how the command interpreter works.
Describe the code.
::Ensure the current directory is the path to this batch file
::This is necessary when you execute the batch file from a shortcut
CD %~dp0
::Create and write to a text file
SET x=%cd%
ECHO %x% This is a new text line > textout.txt
ECHO This is the second line >> textout.txt
PAUSE
ECHO.
ECHO.
::Set up the test files for the remaining instructions
:: write file with space-separated values
ECHO name1 name2 name3 > textout.txt
ECHO 2nd-line parm2 parm 3 >> textout.txt
:: Write file with comma-separated values
SET x=5
SET y=10
ECHO %x%,%y%,now > textout1.txt
ECHO def,ghi,jkl, text >> textout1.txt
PAUSE
ECHO.
ECHO.
::Read first line of text file, read all lines of text file
ECHO off
::Simple way to read the first line of a file
SET/P x=< textout.txt
Echo first line read: %x%
PAUSE
ECHO.
ECHO.
::Remaining examples read the entire file, line by line
::Reading with no delimiters
FOR /f "delims=" %%i IN (textout.txt) DO ECHO Line read as single token: %%i
::Reading with space delimiter
FOR /f "tokens=1-3 delims= " %%i IN (textout.txt) DO ECHO first three tokens: %%i %%j %%k
setlocal enabledelayedexpansion
FOR /f "tokens=1-3 delims= " %%i IN (textout.txt) DO (
ECHO First 3 tokens: %%i %%j %%k
SET Y=%%i
echo The first token is: !y!
set y=!y! added this text
echo The first token with text added is: !y!
)
PAUSE
ECHO.
ECHO.
::Reading with no delimiters
FOR /f "delims=" %%i IN (textout.txt) DO (
ECHO %%i
SET Y=%%i
ECHO THE LINE READ IS: !y!
)
PAUSE
ECHO.
::Reading with comma delimiter
FOR /f "tokens=1-3 delims=," %%i IN (textout1.txt) DO (
ECHO First 3 tokens: %%i %%j %%k
SET Y=%%i
echo The first token is: !y!
set y=!y! added this text
echo The first token with text added is: !y!
)
PAUSE

Create & Execute Windows Command Files -
DO-While & DO-UNTIL Loops

I lied -- The batch command language dosn't have the While and Until loops found in most modern languages. However, it's easy to "pretend" they are there, using IF, GOTO, and labels.
Describe code
Note: Being a programmer for 20 years, I HAVE to make this comment: if you modify the logic to put the test at the bottom of the loop, there are 4 instructions in the loop, instead of 5.
ECHO DO WHILE x less than 10
SET x=0
:LOOP1
SET/A y=%x% * %x%
ECHO x =%x%, x squared = %y%
SET/A x=%x% + 1
IF %x% LSS 10 GOTO LOOP1
PAUSE
ECHO.
ECHO.
ECHO DO UNTIL x greater than 9
SET x=0
:LOOP2
IF %x% GTR 9 GOTO DONE
SET/A y=%x% * %x%
ECHO x =%x%, x squared = %y%
SET/A x=%x% + 1
GOTO LOOP2
:DONE
PAUSE

Create & Execute Windows Command Files -
Extracting Substrings & String Substitution

This video describes functions to extract or replace substrings within strings.
Here is the function to extract a substring from a string.
Set mys=%mys:~s,n%
where s=start position (0 is first), n is the number of characters to return or remove
if n is positive, returns n characters from the start of the string
if n is negative, REMOVES n characters from the end of the string.
And here is the function to substitute a substring within a string.
set mys=%mys:s1=s2%
Where s1 is the string to replace by s2.

All examples use the string [This is]. (Don't type the []!)
Start with 1st char, return 1 char:
set mys=%mys:~0,1%
Start with 2nd char, return 2 chars:
set mys=%mys:~1,2%
Start with 1st char, remove 1 char
set mys=%mys:~0,-1%
Start with 2nd char, remove 2 chars
set mys=%mys:~1,-2%
Replace substring within string
set mys=%mys:s1=s2%
Set mys=%mys:this=the woman%
Use variables in substitution -- you MUST use delayed expansion
set mys=%mys:!y!=!x!%
Code:
::String replacement
ECHO off
SET mys=this is
ECHO %mys%
SET mys1=%mys:~0,1%
ECHO %mys1%
SET mys1=%mys:~1,2%
ECHO %mys1%
SET mys1=%mys:~1,-1%
ECHO %mys1%
SET mys1=%mys:~1,-2%
ECHO %mys1%
SET mys1=%mys:this=the woman%
ECHO %mys1%
SETLOCAL enabledelayedexpansion
SET x=the woman
SET mys1=%mys:this=!x!%
ECHO !mys1!
PAUSE

Create & Execute Windows Command Files -
Search Text Files


This video shows how to search text files for user-entered values. The code example provides a framework for the user to develop code to manage text files. The following videos will show how to provide the file management functions of retrieving, adding, or modifying data from text files. For the file management functions, this code will be converted to a user-callable function.

We're keeping a record counter to report after finding a match. Tokencnt tells the code how many fields to read from each record.
Assumptions for CSV files. every field has at last one char in it, even a space. fields can contain spaces between letters. The user specifies which field to search, and what value to find. Currently set to use comma as a delimiter. Due to problems handling spaces input within strings, the code removes all spaces from fields and search strings before searching. This file is a comma delimited text file, but it works fine for csv files, and those can be input to a spreadsheet program for better display of columns. Due to difficulty handling indexed variables, the code doesn't use them, and a separate test is provided for each field in the record that is to be searched. The code displays the results of the search, and shows either the record found by the search, or the last record read when the search was not successful. Searches continue until the user doesn't enter a field to search, or enters 0,

ECHO off
setlocal enabledelayedexpansion
::Read and process files with or without delimiters
:: number of items in each record
SET tfile=textout1.txt
setlocal enabledelayedexpansion
SET tokencnt=3
SET delimchar=,
if "%delimchar%" == "" (
ECHO no delimiters -- token count changed to 1
set tokencnt=1
)
:NEXTSEARCH
ECHO.
SET reccnt=0
SET itemnum=0
SET/P "itemnum=Number of field to search: "
:: errorcheck itemnum
if %itemnum% GTR %tokencnt% (
ECHO Illegal entry %itennum%: must be numeric and range 1-%tokencnt%
GOTO NEXTSEARCH
)
IF %itemnum% == 0 GOTO QUIT
SET/P itemval="Value to find: "
SET itemval1=%itemval: =%
ECHO.
Echo Searching record field %itemnum% for "%itemval%"
FOR /f "tokens=1-%tokencnt% delims=%delimchar%" %%i IN (%tfile%) DO (
SET/A reccnt = !reccnt! + 1
SET x=%%i
SET x1=!x: =!
SET y=%%j
SET y1=!y: =!
SET z=%%k
SET z1=!z: =!
IF %itemnum% == 1 (
IF %itemval1% == !x1! (
GOTO FOUNDIT
)
)
IF %itemnum% == 2 (
IF %itemval1% == !y1! (
GOTO FOUNDIT
)
)
IF %itemnum% == 3 (
IF %itemval1% == !z1! (
GOTO FOUNDIT
)
)
)
ECHO DID NOT FIND "%itemval%" in field %itemnum%
ECHO !reccnt! records in file
ECHO last rec in file "%x%%delimchar%%y%%delimchar%%z%"
GOTO DONE
:FOUNDIT
ECHO FOUND "%itemval%" in field %itemnum%
ECHO Rec %reccnt%: "%x%%delimchar%%y%%delimchar%%z%"
:DONE
GOTO NEXTSEARCH
:QUIT

Create & Execute Windows Command Files -
Search Gmail Contacts File

This video shows how to modify the code described in the "Search Text Files" video to search a CSV contacts list exported from the Gmail webpage. You should watch the previous video before watching this one. The steps to export the contacts need to be changed for email services other than Gmail, but the code will remain the same.

To copy the BAT code described in this video, click the script webpage link below this video, or type http://webpages.charter.net/tomspage/TTNSite/batfiles.html
Into you browsers address box . To watch the previous video, click the link, or type http://webpages.charter.net/tomspage/TTNSite/batfiles.html.

The modifications described in this video allow you to search the first, middle, and last names or the email addresses in your contacts file and display the record found.
To demonstrate the code, I've exported a contacts group containing only my contact into. Here's how to do that. And here's the CSV file
The file contains adjacent delimiters. They'll be treated by the batch code as single delimiter, and must be separated by at least one character. To reformat the file, execute the replace command twice to replace all ",," with ", ,".
Note: the email address is in field 15.
Here are the code changes needed so you can search the email address field in the file.
The email address is in field 15, so you need to read 15 tokens from the file. (or you could read tokens=1-3,15) The For/F command that reads the records will put the 15th field into variable %%w, so you need to add code to search that variable for user entered values. Ideally, you should add code to reject item number entries other than 1,2,3, or 15, but if you search 4-14 you'll just get a "value not found" messge.


@ECHO off
::Search fields in text file
::Set current directory to folder containing this code
CD %~dp0
::Set defaults (will be overridden if test flag set)
::file name, no. tokens per record, delimiter char
SET tfile=contacts.csv
SET tokencnt=15
SET delimchar=,
SET testflag=no
IF %testflag% == yes SET tfile=temp.txt
IF %testflag% == yes (
SET tokencnt=3
SET delimchar=,
ECHO now,is,the>%tfile%
ECHO 10,20,30>>%tfile%
ECHO tyu, cuy,Uio>>%tfile%
ECHO xyz,,pdq,tuv>>%tfile%
)
::Check whether file exists
IF NOT exist %tfile% (
ECHO.
ECHO File: %tfile% does not exist!
SET/P "junk=Press ENTER to exit!"
GOTO QUIT
)
if "%delimchar%" == "" (
IF %tokencnt% NEQ 1 (
ECHO no delimiters -- token count reduced to 1
set tokencnt=1
)
)
:NEXTSEARCH
ECHO.
SET itemnum=0
::12 lines debug code -- remove/comment to use in "real life"
:: Display test file
setlocal enabledelayedexpansion
IF %testflag% ==yes (
ECHO Test flag is on -- Test file: %tfile%
set reccnt1=0
FOR /f "delims=" %%i IN (%tfile%) DO (
SET/A reccnt1=!reccnt1! + 1
ECHO rec:!reccnt1! %%i
)
)
SET/P "itemnum=Number of field to search: "
SET itemnum=%itemnum:\=a%
SET itemnum=%itemnum:^=a%
SET itemnum=%itemnum:;=a%
SET itemnum=%itemnum:!=a%
:: errorcheck itemnum
if %itemnum% GTR %tokencnt% GOTO BADENTRY
IF %itemnum% LSS 0 GOTO BADENTRY
GOTO CHKDONE
:BADENTRY
ECHO Illegal entry -- must be in range 1-%tokencnt%
GOTO NEXTSEARCH
:CHKDONE
IF %itemnum% == 0 GOTO QUIT
SET/P itemval="Value to find: "
SET itemval1=%itemval: =%
ECHO.
Echo Searching record field %itemnum% for "%itemval%"
SET reccnt=0
FOR /f "tokens=1-%tokencnt% delims=%delimchar%" %%i IN (%tfile%) DO (
SET/A reccnt = !reccnt! + 1
SET x=%%i
SET x1=!x: =!
SET y=%%j
SET y1=!y: =!
SET z=%%k
SET z1=!z: =!
SET c=%%w
SET c1=!c: =!
IF %itemnum% == 1 (
IF %itemval1% == !x1! (
GOTO FOUNDIT
)
)
IF %itemnum% == 2 (
IF %itemval1% == !y1! (
GOTO FOUNDIT
)
)
IF %itemnum% == 3 (
IF %itemval1% == !z1! (
GOTO FOUNDIT
)
)
IF %itemnum% == 15 (
IF %itemval1% == !c1! (
GOTO FOUNDIT
)
)
)
ECHO DID NOT FIND "%itemval%" in field %itemnum%
ECHO %reccnt% records in file
ECHO Rec %reccnt%: "%x%%delimchar%%y%%delimchar%%z%%delimchar%%c%"
GOTO DONE
:FOUNDIT
ECHO FOUND "%itemval%" in field %itemnum%
ECHO Rec %reccnt%: "%x%%delimchar%%y%%delimchar%%z%%delimchar%%c%"
:DONE
GOTO NEXTSEARCH
:QUIT


Create & Execute Windows Command Files -
Arrays


This video shows how to create and use indexed variables (AKA arrays) in batch files. The video shows how to use variables as indices. Numerous examples are given to show what syntax DOES work and what syntax DOESN'T work.

To copy the code described in this video, click the script webpage link below this video, or type http://webpages.charter.net/tomspage/TTNSite/batfiles.html
Into you browsers address box, open the page, then copy the code lines into an empty .BAT file.
Follow the syntax EXACTLY! The command line processor is VERY PARTICULAR. You MUST use delayed expansion (DE) for indexed variables when the indices are variables.
We'll do a detailed code walkthrough, showing the results as we go. THere is some repetition. Syntax do's and don't will be pointed outl.
I've enabled delayed expansion at the beginning. Where it isn't needed, just don't use the "!".
The first code group initializes 3 values in array x, (using indices 0,2, and 3) then uses a FOR loop to set the square of those values into array y, using the same indices.
The next line shows you do NOT need DE outside of the loop setting the variables. (BUT you DO NEED DE if you use variable indices.
The next group shows that you MUST use delayed expansion when referencing arrays with variable indice. What to do and what NOT to do are shown with examples.
The next code group reads a text file and stores the tokens into arrays. Then the arrays are read and displayed.
::arrays
setlocal enabledelayedexpansion
SET x[0]=10
SET x[2]=20
SET x[3]=30
FOR %%i IN (0 2 3) DO (
ECHO !x[%%i]!
SET/A y[%%i]=!x[%%i]! * !x[%%i]!
)
Echo %y[0]% %y[2]% %y[3]%
ECHO.
PAUSE
FOR %%z IN (0 2 3) DO Echo %%z %x[%%z]%
FOR %%z IN (0 2 3) DO Echo %%z !x[%%z]! !y[%%z]!
FOR %%z IN (0 2 3) DO (
Echo %%z !y[%%z]!
SET aa=!y[%%z]!
ECHO aa with DE = !aa!
::Next line DOESN'T WORK
SET aa=%y[%%z]%
ECHO aa with percent = !aa!
SET aa=%y[3]%
ECHO aa with constant index = !aa!
)
set ix=3
:: next 2 lines DON'T WORK
ECHO without DE %x[%ix%]%
ECHO Per Cent first %x[!ix!]%
ECHO with DE !x[%ix%]!
PAUSE
ECHO.
::Save text file contents in array
SET ix=0
FOR /F "tokens=1-3 delims=," %%i IN (temp1.txt) DO (
ECHO First 3 tokens: %%i,%%j,%%k
SET/A ix=ix+1
SET x[!ix!]=%%i
SET y[!ix!]=%%j
SET z[!ix!]=%%k
)

PAUSE
ECHO.
ECHO File contents from array
FOR /L %%q IN (1,1,%ix%) DO ECHO !x[%%q]!,!y[%%q]!,!z[%%q]!
PAUSE

Create & Execute Windows Command Files -
String Input Function

This is the first of several general-purpose batch code input functions to prompt for and accept user inputs. These functions will serve as building-blocks to help you develop your own special purpose programs. The functions will be used in the File Management Program that will be described in a later video.
Many useful code sections (snippets) are described in this video, and those will be collected in a video "How Do I?" in this same playlist.

To copy the BAT code described in this video, click the script webpage link below this video, or type http://webpages.charter.net/tomspage/TTNSite/batfiles.html
Into your browsers address box . Save the test file with any name as a .bat file. Save the get_string function in file get_string.bat. Save both files in the save folder (or on the desktop).
Problems to avoid: While learning bacch code programming, I encountered many "idiosyncracies" of batch code. Some of these give error messages, some just cause the code window to vanish.
Using labels and comments. NEVER use 2 adjacent semi-colon comments or labels within a code block. NEVER put a label or semi-colon comment just before the closing ")" in a block.
Strings: Don't try to compare strings containing embedded spaces. ALWAYS put quotes around strings being compared in case either string is empty.
(IF "%a%"=="%b%" command-to-execute, or IF "!%1!"=="%b%" command-to-execute
Entries can be restricted to names in a list, and the list can be optionally hidden (for example when entering passwords, or user names). A default value is returned if the user just presses enter, after the prompt. The function has a built-in default value, and the programmer can also pass the default value to the function in the CALL.
The variable for the returned value MUST be given in the call. The other parameters at the beginning of the function let the programmer easily customize the function.
Va
Many coding and debugging hints are given in the code walkthroughs, and functions ares demonstrated using both valid and invalid entries.
The test driver is shown below, followed by the function code.
REM Test driver for get_string
@ECHO off
REM Parms (defaults in not entered)
REM value: Returned string, prompt: Prompt,
REM default(NONE): value returned if user doesn't enter anything
REM choices(): list of acceptable inputs
REM disp_choices(yes): yes to display acceptable inputs
setlocal enabledelayedexpansion
REM parameters must be entered in the order given
REM ALL parameters except value may be omitted by eliminating all chars
REM after the "=" in the set commands.
REM You can eliminate consecutive parms from the right end of the call
REM (parm 5, or parms 4-5, or parms 3-5, or parms 2-5)
SET prompt=Please enter your name
SET default=none_given
SET choices=tom joe bill
SET shochoices=NO

:next
REM CALL get_string value prompt default choices shochoices
call get_string value prompt default choices shochoices
if %errorlevel%==99 (
ECHO.
ECHO error %errorlevel% returned from called file get_string
ECHO press any char to terminate file %~n0
PAUSE
GOTO:eof
)
echo returned value=!value!
IF not !value! equ joe goto next

REM Get_string -- string input function
setlocal enabledelayedexpansion
ECHO off
REM Prompts for input string, checks against list of values

REM Input parameters
REM %1 - returned value, %2 - prompt, %3 - default,
REM %4 - list of values, %5 (Y/N) Display choices,

REM return value variable %1 must be specified
IF "%1"=="" (
ECHO Call to file %~n0 is missing
ECHO the return value parameter
ECHO Returning error code 99 to caller
EXIT/b 99
)

REM Program defaults -- change these to customize the code
REM set values to use if none specified in the call
SET ddefault=NONE
SET dchoices=any valid string
SET dshochoices=yes
REM prompt character
SET prmptchar=^>

REM Copy input parms to vars to improve readibility
SET prompt=!%2!
SET default=!%3!
SET choices=!%4!
SET shochoices=!%5!
IF "%default%"=="" SET default=%ddefault%
IF "%choices%"=="" SET choices=anystring
IF "%shochoices%"=="" SET shochoices=%dshochoices%

:GETVALUE
ECHO.
REM optionally show user what entries are allowed
IF /i "%shochoices%"=="yes" (
IF "%choices%"=="anystring" (
ECHO Enter any string
) ELSE (
ECHO choices: %choices%
)
)

REM prompt for user input
SET value=%default%
SET/P "value=%prompt%%prmptchar%"

REM remove any illegal chars user may have entered
SET value=%value:,=%
if "%value%"=="" GOTO NOWEMPTY
SET value=%value:;=%
if "%value%"=="" GOTO NOWEMPTY
SET value=%value::=%
if "%value%"=="" GOTO NOWEMPTY
SET value=%value:^^=%
if "%value%"=="" GOTO NOWEMPTY
REM check whether only spaces were entered
SET value1=%value: =%
IF "%value1%"=="" GOTO NOWEMPTY
GOTO CHKVALUE

:NOWEMPTY
SET value=%default%
:CHKVALUE
REM don't check input if nothing entered
IF /i "%value%"=="%default%" GOTO DONE1
REM Check whether list of acceptable values given
REM if not, we don't do any error checking
IF /i "%choices%"=="anystring" GOTO DONE1
REM check whether entry is in choices
FOR %%a IN (%choices%) DO (
if "%%a"=="%value%" GOTO DONE1
)
GOTO BADVAL
:DONE1
( endlocal
set %1=%value%
)
GOTO:eof
:BADVAL
ECHO Illegal entry
GOTO GETVALUE

Create & Execute Windows Command Files -
String Input Function

This is the first of several general-purpose batch code input functions. These functions will serve as building-blocks to help you develop your own special purpose programs. This function (get_string) prompts for and accepts user input strings. The functions will be used in the File Management Program that will be described in a later video.
Many useful code sections (snippets) are described in these videos, and those will be collected in a video "How Do I?" in this same playlist.

You can copy the function and it's test driver described in this video from my website. Click the script webpage link below this video, or type http://webpages.charter.net/tomspage/TTNSite/batfiles.html
Into your browsers address box . Copy the test file code into a .bat file with any name. Save the get_string function in file get_string.bat. Both files must be in the same folder (or on the desktop).

(SHOW test driver)
This video is shows how to use the get_string function, using this test driver. The next video will do a detailed "walkthru" of the function code, and describe how the code works, so you can customize it to fit your needs.
Function parameters allow the programmer to customize function operation for each input his program needs.
These are the parameters.
As mentioned, the function provides default values for each parameter omitted. The programmer can specify parameter values by:
Using variables in the call, and setting their values before calling the function. Quotes are OPTIONAL here. The parameter names can be changed, but the name in the call and in the SET much match. Parameters must be specified in the order shown in the call. Parameters can be omitted by deleting their SET instruction, by setting their values to null (erasing everything after the "="), , or by replacing the parameter name in the call with x (or the name of any other variable that is NOT initialized in your program.
Lastly, the programmer can insert values in the CALL instruction by enclosing them in quotes. Quotes are REQUIRED in the call statement.
Paste the test driver below into an empty .bat file anywhere on your computer. The get_string function listed after the test driver must be saved in a separate file "get_string.bat" in the same folder as the test driver. Or put them both on your desktop.
I'll demonstrate the functions with the built-in parameter defaults, and with parm values specified in the test program.

Paste this test-driver into an empty .bat file. Use any name.

@ECHO off
REM Test driver for get_string
setlocal enabledelayedexpansion
REM Parms (defaults in not entered)
REM value: Returned string
REM prompt: Prompt,
REM default(NONE): value returned if user doesn't enter anything
REM choices(You may enter any string): list of acceptable inputs
REM shochoices(yes): yes to display acceptable inputs
REM parameters must be entered in the order given
REM ALL parameters except value may be omitted by eliminating all chars
REM after the "=" in the set commands, or by deleting the SET instruction.
REM You can eliminate consecutive parms from the right end of the CALL.
REM You can insert values for parms in the CALL, enclosed in quotes, or
REM eliminate parms by putting the name of an undefined variable at their
REM position in the CALL. I use x (without quotes).

REM Initialize varibles to use in the CALL
SET promptt=Please enter your name
SET default=none given
SET choices=tom bill
SET shochoices=yes

:next
CALL get_string value promptt default choices shochoices
REM CALL get_string value promptt default choices shochoices

REM check whether programmer omitted value parm in call
if %errorlevel%==99 (
ECHO.
ECHO error %errorlevel% returned from called file get_string
ECHO press any char to terminate file %~n0
PAUSE
GOTO:eof
)
echo returned value=!value!
IF not "!value!" == "joe" goto next

Paste function get_string into a .bat file named get_string.bat. It must be in the same folder as the test file, or both may be on the desktop.

@ECHO off
REM Function get_string - general-purpose string input function
setlocal enabledelayedexpansion

REM Input parameters
REM %1 - returned value, %2 - prompt, %3 - default,
REM %4 - list of values, %5 (Y/N) Display choices,

REM return value variable %1 must be specified
IF "%1"=="" (
ECHO Call to file %~n0 is missing
ECHO the return value parameter
ECHO Returning error code 99 to caller
EXIT/b 99
)

REM Program defaults
REM prompt char
set prmptchar=^>
REM Change these to customize the code
REM These defaults are used if they are
REM not specified in the call statement
REM string returned when no entry is typed,
REM msg displayed when choices are not specified
REM and whether or not to show the choices list or msg
SET ddefault=NONE
SET dchoices=You may enter any string
SET dshochoices=yes

REM inpt parms to vars to improve code readibility
set iprompt=!%2!
SET idefault=!%3!
SET ichoices=!%4!
SET ishochoices=!%5!

REM init the program vars to their defaults
REM echo iprompt=!iprompt! prompt=!prompt!
SET pprompt=nodefault
SET pdefault=!ddefault!
SET pchoices=!dchoices!
SET pshochoices=!dshochoices!
REM set defaults for missing parameters

REM check whether user has set parms
CALL:chknoentry pprompt iprompt %2
if "!pprompt!"=="nodefault" SET pprompt=
CALL:chknoentry pdefault idefault %3
CALL:chknoentry pchoices ichoices %4
CALL:chknoentry pshochoices ishochoices %5

REM fail safe for pgm errors
IF "!pdefault!"=="" ECHO error in parm 3
IF "!pchoices!"=="" ECHO error in parm 4
IF "!pshochoices!"=="" ECHO error in parm 5
IF "!pshochoices!"=="nothing" ECHO error in parm 5
REM ECHO prompt=!pprompt!, def=!pdefault!, choi=!pchoices!, shochoi=!pshochoices!

:GETVALUE
ECHO.
REM set initial value for set/p command
SET value=%pdefault%

REM optionally show user what entries are allowed
IF "!pshochoices!"=="yes" ECHO choices: !pchoices!
SET/P "value=!pprompt!!prmptchar!"

REM remove any illegal chars user may have entered
SET value=%value:,=%
if "%value%"=="" GOTO NOWEMPTY
SET value=%value:;=%
if "%value%"=="" GOTO NOWEMPTY
SET value=%value::=%
if "%value%"=="" GOTO NOWEMPTY
SET value=%value:^^=%
if "%value%"=="" GOTO NOWEMPTY
REM check whether only spaces were entered
SET value1=%value: =%
IF "%value1%"=="" GOTO NOWEMPTY
GOTO CHKVALUE

REM return default value if user only entered illegal chars or spaces
:NOWEMPTY
SET value=!pdefault!

REM check the user input value
REM skip if nothing entered (pgm has set those to default)
:CHKVALUE
IF /i "!value!"=="!pdefault!" GOTO DONE1
REM Check whether list of acceptable values given
REM if not, we don't do any error checking
IF /i "!pchoices!"=="!dchoices!" GOTO DONE1
REM check whether entry is in list of choices
FOR %%a IN (!pchoices!) DO (
if "%%a"=="!value!" GOTO DONE1
)
ECHO Illegal entry
GOTO GETVALUE

:DONE1
( endlocal
set %~1=%value%
)
GOTO:eof

:chknoentry
REM ECHO chknoentry 1 %1 2 !%1! 3 %2 4 !%2! 5 %3 6 !%3!
REM Replaces working entry %1 with the input %2
REM process parameter included in call statement
REM (It must be enclosed in quotes)
REM The parm value to be used has already been set to the program default value
REM chknoentry will override the program default if the user has entered another value

REM this test is true UNLESS the parm is omitted from the call statement
REM Echo 3RD PARM %3 1 !%3!
if NOT "%~3"=="" (
REM ECHO test 1 true
REM CALL contains either a valid parm name, an undefined var name, or quoted string
set p1=%3
REM ECHO p1=!p1!
SET firstchar=!p1:~0,1!
if "!firstchar!!firstchar!"=="""" (
REM CALL contains quoted string
set outparm=!p1!
GOTO FIN
)
)
REM echo input not empty
REM parm is missing from the call, or call contains undefined or defined var name
IF "!%3!"=="" (
REM parm is missing from call, there is undefined var name in call,
REM parm set to null, or there is no set for this var
REM echo test 2 true
SET outparm=nothing
GOTO FIN
)
REM ECHO parm is empty
REM
REM Set instruction assigns value to the vazr
IF not "!%~2!"=="" (
REM ECHO test 4 true
REM input value was init with SET, with or wthout quotes
SET outparm=!%~2!
REM echo 4 outparm=!outparm!
)
:FIN
REM ECHO outparm before final check !outparm!
REM The input value has not been set, for a variety of reasons
REM The default value will be used by get_string
if "!outparm!"=="nothing" (
REM Echo test 5 true
REM echo exiting without change
GOTO:eof
) ELSE (
SET outparm=!outparm:"=!
)
(endlocal
REM set output value
SET "%~1=%outparm%"
)
GOTO:eof

Create & Execute Windows Command Files -
Integer Input Function

This function (get_integer) prompts the user for integers, then error checks and accepts inputs. Decimal,octal, and hexadecimal inputs are allowed. The functions will be used in the File Management Program that will be described in a later video.
Many useful code sections (snippets) are described in these videos, and those will be collected in a video "How Do I?" in this same playlist.

 

You can copy the function and it's test driver described in this video from my website. Click the script webpage link below this video, or type http://webpages.charter.net/tomspage/TTNSite/batfiles.html
Into your browsers address box . Copy the test file code into a .bat file with any name. Save the get_integer function in file get_integer.bat. Both files must be in the same folder (or on the desktop).

(SHOW test driver)
This video is describes the code for the test driver and the function. Common code already described for the get_string function will not be described again.
Here is the test driver.
Function parameters allow the programmer to customize function operation for each input his program needs.
These are the parameters for the get_integer function.
(Describe them). Parms can be given in SET instructions, or included in the CALL statement. Refer to the description in video "String Input Function" for how to use parms in my input functions.
Paste the test driver below into an empty .bat file anywhere on your computer. The get_integer function listed after the test driver must be saved in a separate file "get_integer.bat" in the same folder as the test driver. Or put them both on your desktop.
I'll demonstrate the functions with the built-in parameter defaults, and with parm values specified in the test program.


Paste this test-driver into an empty .bat file. Use any name.

@ECHO off
setlocal enabledelayedexpansion
REM Parms (defaults in not entered)
REM value: Returned integer
REM promptt(Enter number): Prompt, do not spell this var as "prompt"
REM - system var conflict
REM default(NONE): value returned if user doesn't enter anything
REM min(0) - lowest value acepted
REM max(10) - highest value accepted
REM chkrange(yes) - check the range of the input
REM shorange(yes) - display min and max values
REM parameters must be entered in the order given
REM ALL parameters except value may be omitted by eliminating all chars
REM after the "=" in the set commands, or by deleting the SET instruction.
REM You can eliminate consecutive parms from the right end of the CALL.
REM You can insert values for parms in the CALL, enclosed in quotes, or
REM eliminate parms by putting the name of an undefined variable at their
REM position in the CALL. I use x (without quotes).

REM Initialize varibles to use in the CALL
SET promptt=Please enter your number
SET default=50
SET chkrange=yes
SET min=0
SET max=020
SET shorange=yes

:next
CALL get_integer value promptt default chkrange min "020" shorange
REM CALL get_integer value promptt default chkrange min max shorange

REM check whether programmer omitted value parm in call
if %errorlevel%==99 (
ECHO.
ECHO error %errorlevel% returned from called file get_integer
ECHO press any char to terminate file %~n0
PAUSE
GOTO:eof
)
echo returned value=!value!
ECHO !default!
IF not "!value!" == "!default!" goto next

Paste function get_integer into a .bat file named get_integer.bat. It must be in the same folder as the test file, or both may be on the desktop.

@ECHO off
REM Function get_integer - general-purpose integer input function
REM that prompts for error checks and accepts decimal, octal,
REM or hexadecimal integers
setlocal enabledelayedexpansion

REM Input parameters
REM %1 - returned value, %2 - prompt, %3 - default,
REM %4 - check range, %5 - min, %6 max, %7 show range

REM return value variable %1 must be specified
IF "%1"=="" (
ECHO Call to file %~n0 is missing
ECHO the return value parameter
ECHO Returning error code 99 to caller
EXIT/b 99
)

REM Program defaults
REM prompt char
set prmptchar=^>
REM Change these to customize the code
REM These defaults are used if they are
REM not specified in the call statement
REM string returned when no entry is typed,
REM msg displayed when choices are not specified
REM and whether or not to show the choices list or msg
SET ddefault=NONE
SET dchkrange=yes
SET dmin=0
SET dmax=10
SET dshorange=yes

REM copy input parms to vars to improve code readibility
set iprompt=!%2!
SET idefault=!%3!
SET ichkrange=!%4!
SET imin=!%5!
SET imax=!%6!
SET ishorange=!%7!

REM init the program vars to their defaults
REM echo iprompt=!iprompt! prompt=!prompt!
SET pprompt=nodefault
SET pdefault=!ddefault!
SET pchkrange=!dchkrange!
SET pmin=!dmin!
SET pmax=!dmax!
SET pshorange=!dshorange!
REM set defaults for missing parameters

REM check whether caller set parms
CALL:chknoentry pprompt iprompt %2
if "!pprompt!"=="nodefault" SET pprompt=
CALL:chknoentry pdefault idefault %3
CALL:chknoentry pchkrange ichkrange %4
CALL:chknoentry pmin imin %5
CALL:chknoentry pmax imax %6
CALL:chknoentry pshorange ishorange %7

:GETVALUE
ECHO.
REM set initial value for set/p command
SET value=%pdefault%

REM optionally show user what entries are allowed
IF "!pshorange!"=="yes" ECHO Range: (!pmin!-!pmax!)
SET/P "value=!pprompt!!prmptchar!"

REM remove any illegal chars user may have entered
SET value=%value:,=%
if "%value%"=="" GOTO NOWEMPTY
SET value=%value:;=%
if "%value%"=="" GOTO NOWEMPTY
SET value=%value::=%
if "%value%"=="" GOTO NOWEMPTY
SET value=%value:^^=%
if "%value%"=="" GOTO NOWEMPTY
REM check whether only spaces were entered
SET value1=%value: =%
IF "%value1%"=="" GOTO NOWEMPTY
GOTO CHKVALUE

REM return default value if user only entered illegal chars or spaces
:NOWEMPTY
SET value=!pdefault!

REM check the user input value
:CHKVALUE
REM echo val,def !value! !pdefault!
IF /i "!value!"=="!pdefault!" GOTO DONE1
REM verify that input is number
SET/A temp1=!value!+0 2>NUL
REM ECHO temp1=!temp1! value=!value!
IF "!temp1!"=="" GOTO BADVAL
REM echo ok to chk value
if "!temp1!"=="0" IF NOT "!value!"=="0" GOTO BADVAL
:CHKIT
REM Check whether range given
REM if not, we don't do any error checking
IF "!pchkrange!"=="no" GOTO DONE1
IF !temp1! LSS !pmin! GOTO BADVAL
IF !temp1! GTR !pmax! GOTO BADVAL
GOTO :DONE1

:BADVAL
ECHO ERROR -- value(!value!) is non numeric or out of range (!pmin!-!pmax!)
GOTO GETVALUE

:DONE1
( endlocal
set %~1=%value%
)
GOTO:eof

:chknoentry
REM Process user parm input value
REM inputs %1 working value for parm - has been set to default for this parm
REM %2 parm variable or value passed as a get_string input parameter
REM %3 unexpanded parm value or value passed into the calling program

REM Replaces working entry %1 with the value derived from user entry from the call %2
REM chknoentry will override the program default if the user
Rem has passed a value via the CALL to get_string

REM this test is true UNLESS the parm is omitted from the call statement
if NOT "%~3"=="" (
REM CALL contains either a valid parm name, an undefined var name, or quoted string
set p1=%3
SET firstchar=!p1:~0,1!
if "!firstchar!!firstchar!"=="""" (
set outparm=!p1!
GOTO FIN
)
)
REM parm is missing from the call, or call contains undefined or defined var name
IF "!%3!"=="" (
REM parm is missing from call, there is undefined var name in call,
REM parm set to null, or there is no set for this var
SET outparm=nothing
GOTO FIN
)
REM ECHO parm is empty
REM
REM Set instruction assigns value to the var
IF not "!%~2!"=="" (
SET outparm=!%~2!
)
:FIN
REM The input value has not been set, for a variety of reasons
REM The default value will be used by get_string
if "!outparm!"=="nothing" (
REM echo exiting without change
GOTO:eof
) ELSE (
SET outparm=!outparm:"=!
)
(endlocal
REM set output value
SET "%~1=%outparm%"
)
GOTO:eof

 

Create & Execute Windows Command Files -
CMD Input Function

This video describes the get_cmd input function. This function displays a list of commands expected from the user, then prompts for a selection. The calling program passes the function a command list name. The function then searches a text datafile for the specified list, fetches and displays the commands in the list, then prompts the user to select a command. Get_cmd returns a default command selection if none is entered. The programmer would then process the user's command selection
How to copy the function and test driver code from my web page was described in the previous video "String Input Function".

Here is the datafile used by this function. It is a comma separated value file, and could also be a .CSV file. Each command list contains: header rec, preamble records, and command records. Each record must have at least 4 fields, with unused fields containing at least one space or other character.

This function uses a comment-delimited text file containing command lists.
This function uses the get_string function described in a previous video, with a slight enhancement. First, we'll describe the change to the get_string function, then we'll describe the command list datafile, and the get_cmd function. A future video will describe file management functions to create/edit the datafile containing the command lists.
Note: get_string.bat, Cmd_list.txt, get_cmd.bat, and test get_cmd.bat must all be in the same folder (or on the desktop) before executing test get_cmd.bat.
The get_string function has a new 6th parameter. Setting "yes" tells get_string to return to the caller when an invalid string is entered. Get_cmd calls get_string for prompting, and reprompts with the command list when get_string returns an invalid entry.

Save get_string.bat
@ECHO off
REM Function get_string - general-purpose string input function
setlocal enabledelayedexpansion
REM echo enter getstring
REM Input parameters
REM %1 - returned value, %2 - prompt, %3 - default,
REM %4 - list of values, %5 (Y/N) Display choices, %6 - return after illegal entry (Y/N)

REM return value variable %1 must be specified
IF "%1"=="" (
ECHO Call to file %~n0 is missing
ECHO the return value parameter
ECHO Returning error code 99 to caller
EXIT/b 99
)

REM Program defaults
REM prompt char
set prmptchar=^>
REM Change these to customize the code
REM These defaults are used if they are
REM not specified in the call statement
REM string returned when no entry is typed,
REM msg displayed when choices are not specified
REM and whether or not to show the choices list or msg
SET ddefault=NONE
SET dchoices=You may enter any string
SET dshochoices=yes
SET dretillegal=no

REM inpt parms to vars to improve code readibility
set iprompt=!%2!
SET idefault=!%3!
SET ichoices=!%4!
SET ishochoices=!%5!
SET iretillegal=!%6!

REM init the program vars to their defaults
REM echo iprompt=!iprompt! prompt=!prompt!
SET pprompt=nodefault
SET pdefault=!ddefault!
SET pchoices=!dchoices!
SET pshochoices=!dshochoices!
SET pretillegal=!dretillegal!
REM set defaults for missing parameters

REM check whether caller set parms
CALL:chknoentry pprompt iprompt %2
if "!pprompt!"=="nodefault" SET pprompt=
CALL:chknoentry pdefault idefault %3
CALL:chknoentry pchoices ichoices %4
CALL:chknoentry pshochoices ishochoices %5
CALL:chknoentry pretillegal ipretillegal %6

REM fail safe for pgm errors
IF "!pdefault!"=="" ECHO error in parm 3
IF "!pchoices!"=="" ECHO error in parm 4
IF "!pshochoices!"=="" ECHO error in parm 5
IF "!pshochoices!"=="nothing" ECHO error in parm 5
IF "!pretillegal!"=="" ECHO error in parm 6
REM ECHO getstring parms prompt=!pprompt!, def=!pdefault!, choi=!pchoices!, shochoi=!pshochoices!, retillegal=!pretillegal!

:GETVALUE
ECHO.
REM set initial value for set/p command
SET value=%pdefault%

REM optionally show user what entries are allowed
IF "!pshochoices!"=="yes" ECHO choices: !pchoices!
SET/P "value=!pprompt!!prmptchar!"

REM remove any illegal chars user may have entered
SET value=%value:,=%
if "%value%"=="" GOTO NOWEMPTY
SET value=%value:;=%
if "%value%"=="" GOTO NOWEMPTY
SET value=%value::=%
if "%value%"=="" GOTO NOWEMPTY
SET value=%value:^^=%
if "%value%"=="" GOTO NOWEMPTY
REM check whether only spaces were entered
SET value1=%value: =%
IF "%value1%"=="" GOTO NOWEMPTY
GOTO CHKVALUE

REM return default value if user only entered illegal chars or spaces
:NOWEMPTY
SET value=!pdefault!

REM check the user input value
REM skip if nothing entered (pgm has set those to default)
:CHKVALUE
REM echo val,def !value! !pdefault! p !pchoices! d !dchoices!
IF /i "!value!"=="!pdefault!" GOTO DONE1
REM Check whether list of acceptable values given
REM if not, we don't do any error checking
IF /i "!pchoices!"=="!dchoices!" GOTO DONE1
REM check whether entry is in list of choices
FOR %%a IN (!pchoices!) DO (
if "%%a"=="!value!" GOTO DONE1
)
IF pretillegal=="no" (
ECHO Illegal entry -- try again^^!
GOTO GETVALUE
)
SET value=illegal
REM echo exiting on illegal entry

:DONE1
( endlocal
set %~1=%value%
REM echo exit getstring
)
GOTO:eof

:chknoentry
REM ECHO chknoentry 1 %1 2 !%1! 3 %2 4 !%2! 5 %3 6 !%3!
REM Process user parm input value
REM inputs %1 working value for parm - has been set to default for this parm
REM %2 parm variable or value passed as a get_string input parameter
REM %3 unexpanded parm value or value passed into the calling program

REM Replaces working entry %1 with the value derived from user entry from the call %2
REM chknoentry will override the program default if the user
Rem has passed a value via the CALL to get_string

REM this test is true UNLESS the parm is omitted from the call statement
REM Echo 3RD PARM %3 1 !%3!
if NOT "%~3"=="" (
REM ECHO test 1 true
REM CALL contains either a valid parm name, an undefined var name, or quoted string
set p1=%3
REM ECHO p1=!p1!
SET firstchar=!p1:~0,1!
if "!firstchar!!firstchar!"=="""" (
REM echo %1 test1a true
set outparm=!p1!
GOTO FIN
)
)
REM echo input not empty
REM parm is missing from the call, or call contains undefined or defined var name
IF "!%3!"=="" (
REM parm is missing from call, there is undefined var name in call,
REM parm set to null, or there is no set for this var
REM echo test 2 true
SET outparm=nothing
GOTO FIN
)
REM ECHO parm is empty
REM
REM Set instruction assigns value to the var
IF not "!%~2!"=="" (
REM ECHO test 4 true
REM input value was init with SET, with or without quotes
SET outparm=!%~2!
REM echo 4 outparm=!outparm!
)
:FIN
REM ECHO outparm before final check !outparm!
REM The input value has not been set, for a variety of reasons
REM The default value will be used by get_string
if "!outparm!"=="nothing" (
REM Echo test 5 true
REM echo exiting without change
GOTO:eof
) ELSE (
SET outparm=!outparm:"=!
)
(endlocal
REM set output value
SET "%~1=%outparm%"
)
GOTO:eof

Save as cmd_list.txt
1,editrecord,Enter command,r,a
2,Edit records -- Select a command, ,x
2, or press enter to leave this command group., ,
3,f,find record, , ,
3,e,edit record, , ,
3,d,delete record, , ,
3,m,move record, , ,
3,c,copy record, , ,
3,r,return (no cmd entered), , ,
1,editrecord1,Enter your ans,r
2,Edit records1 --Select a command - or press enter to leave this command group.
3,f,find record, , ,
3,e,edit record, , ,
3,d,delete record, , ,
3,m,move record, , ,
3,c,copy record, , ,
3,r,return (no cmd entered), , ,
1,filemanage,Enter file command,NONE
2,File management functions -- Select a command - or press enter to leave this command group.
3,c,copy file, , ,
3,d,delete file, , ,
3,f,find file, , ,
3,r,return (no cmd entered), , ,
1,filemanage1,Enter file command,r,a
2,File management functions -- Select a command, or press enter to leave this command group.
3,c 2,copy file, , ,
3,d,delete file, , ,
3,f,find file, , ,
3,r,return (no cmd entered), , ,
1,now is,Enter file command,r,a
2,File management functions -- Select a command, or press enter to leave this command group.
3,c,copy file, , ,
3,d,delete file, , ,
3,f,find file, , ,
3,r,return (no cmd entered), , ,

Save get_cmd.bat
@ECHO off
REM Search for requested command, display header and list of commands
REM Prompt user for entry, return selected command
REM %1 (input) - command list to display,
REM %2 (output) - command selected (NONE) if none selected
REM search for command
REM rec id codes
REM hcode - code for header rec, pcode - preamble, ccode - command rec
setlocal enabledelayedexpansion

SET cmdlist=%~1
REM echo cmdlist=!cmdlist!
SET fname=cmd_list.txt
SET defans=BADLISTNAME
SET hcode=1
SET pcode=2
SET ccode=3
set pmtchar=^>
SET promptt=
CALL:get_cmd_list cmdlist fname cname defans promptt reccnt1 defans1
REM ECHO get_cmd_list returned !cname!
REM echo cname=!cname!, default=!defans!
:RETRY
REM echo reccnt1 !reccnt1!
IF NOT "!cname!"=="!defans!" (
SET reccnt=!reccnt1!
REM Echo reccnt !reccnt! reccnt1 !reccnt1!
REM ECHO calling shocmds clist !cname! reccnt !reccnt! defans1 !defans1!
CALL:shocmds clist reccnt defans1
REM echo reccnt1 after shocmds !reccnt1!
CALL get_string value "!promptt!" "!defans1!" "!clist!" "no" "yes"
REM echo from getstring
IF "!value!"=="illegal" (
ECHO Illegal command entered -- try again^^!
GOTO RETRY
)
REM ECHO value entered=!value!
SET pout=!value!
) ELSE (
REM ECHO Command list "!cmdlist!" not found in data file
SET pout=!cname!
)
(endlocal
REM echo pout=%pout%
SET "%~2=%pout%"
)
GOTO:eof

:shocmds
REM parameters
REM %1 - list of commands for this command list
REM %2 - record number of header rec
REM %3 - default command
REM ECHO shocmds file=!fname! reccnt=!reccnt! hcode=x!hcode!x pcode=x!pcode!x ccode=x!ccode!x
SET reccnt2=!%2!
REM echo shocmds reccnt1 !reccnt1!
ECHO.
FOR /F "SKIP=%reccnt1% tokens=1-3 delims=," %%i in (!fname!) DO (
SET/A reccnt2=!reccnt2!+1
REM ECHO is command line? rec !reccnt! %%i, %%j, hcode=x!hcode!x ccode=x!ccode!x
IF "%%i"=="!hcode!" GOTO FIN
IF "%%i"=="!ccode!" (
SET/A cmdcnt=!cmdcnt!+1
REM echo command code
REM echo cmd x%%jx defans1 x!%3!x
IF "%%j"=="!%3!" (
ECHO %%j - %%k -- default
) ELSE (
ECHO %%j - %%k
)
set CMDLST=!CMDLST! %%j
REM pause
) ELSE (
REM echo is preamble?
REM pause
IF "%%i"=="!pcode!" Echo %%j
)
)

:FIN
(endlocal
SET "%~1=%CMDLST%"
REM echo rec=!reccnt! rec1=!reccnt1!
)
GOTO:eof

:get_cmd_list
REM parameters
REM %1 - name of command list
REM %2 - data file name
REM %3 - (out) name of command list found or default for not found
REM %4 - value to return if cmd list not found
REM %5 - (out) prompt string for this command list
REM %6 - (out) record number for header record found
REM %7 - (out) default command
REM echo get_cmd_listx parmsx 1 !%1! 2 !%2! 4 !%4! 5 !%5!
REM set parms
SET reccnt=0
SET name=!%1!
FOR /F "tokens=1-4 delims=," %%i in (!%2!) DO (
SET/A reccnt=!reccnt!+1
Set name1=%%j
REM echo hcode=!hcode! name1=!name1!
IF "%%i"=="!hcode!" (
REM echo compare cmd name "!name1!" "!name!"
if "!name1!"=="!name!" (
REM ECHO found it
REM ECHO rec !reccnt!: %%i,!name1!
SET p3=%%j
SET p7=%%l
set pmpt=%%k
GOTO DONE
)
)
)
REM echo not found
SET p3=!%4!
SET pmpt=promptnotfound
SET reccnt=0
REM echo p3=!p3!
:DONE
(endlocal
SET "%~3=%p3%"
SET "%~5=%pmpt%"
set "%~6=%reccnt%"
set "%~7=%p7%"
)
GOTO:eof

Save test get_cmd.bat
@ECHO off
:GETNAME
ECHO.
SET cmdlist="NONE"
SET/P "cmdlist=Enter name of command list>"
IF "%cmdlist%"=="NONE" GOTO DONE
CALL get_cmd "%cmdlist%",cmdname
REM programmer would insert code here to process the command selected by the user.
echo command entered=%cmdname%
GOTO GETNAME
:DONE

Create & Execute Windows Command Files -
CMD Function Walkthru

This video is a code walkthru for the get_cmd input function. Code described in previous videos will be pointed out, and new code will be described in detail.

How to copy the function and test driver code from my web page was described in the previous video "String Input Function".

Notes:
Get_string.bat, cmd_list.txt, get_cmd.bat, and test get_cmd.bat must all be in the same folder (or on the desktop) before executing test get_cmd.bat.
All the code required to execute this function is given below. Only test get_cmd.bat, and get_cmd.bat will be described here. Some "cleanup" to the comments has been done since the last video. The code has not changed.
A parameter was added to the get_string function described in video "String Input Function". The change was described in video "Command Input Function".
The test function loops, calling get_cmd for each command list entered by the user. The command list name is passed as parameter 1, and the command entered by the user is returned as parameter 2.

Parameters (summary - don't try to execute these)
:get_cmd
REM %1 (in) - command list to display,
REM %2 (out) - command selected (NONE) if none selected

:get_cmd_list
REM parameters
REM %1 - (in) name of command list
REM %2 - (in) data file name
REM %3 - (out) name of command list found or default for not found
REM %4 - (in) value to return if cmd list not found
REM %5 - (out) prompt string for this command list
REM %6 - (out) record number for header record found
REM %7 - (out) default command

:shocmds
REM parameters
REM %1 - (out) list of commands for this command list
REM %2 - (in) record number of header rec
REM %3 - default command


:get_string
REM %1 - returned value, %2 - prompt, %3 - default,
REM %4 - list of values, %5 (Y/N) Display choices, %6 - return after illegal entry (Y/N)

Use the code from the previous script.

Create & Execute Windows Command Files -
Using The CMD Input Function


This video show how to incorporate the CMD input function into your program. The CMD input function and its test driver were described in video "Command Input Function".
How to copy the function and test driver code from my web page was described in the previous video "String Input Function".

@ECHO off
:GETNAME
ECHO.
CALL get_cmd "editrecord",cmdname
REM code to process commands
GOTO ER%cmdname% 2>null || (
ECHO label "er%cmdname%" not found
set/p junk="Press "enter" to terminate program!"
)
REM This code processes each command entered from command list "editrecord".
:erf
ECHO code to process %cmdname% command
GOTO GETNAME
:ere
ECHO code to process %cmdname% command
GOTO GETNAME
:erd
ECHO code to process %cmdname% command
GOTO GETNAME
:erm
ECHO code to process %cmdname% command
GOTO GETNAME

All other code is shown in the previous script for "Command Input Function".

Create & Execute Windows Command Files -
Bubble Sort Function


This video shows a "bubble sort" written in batch code. A future video will show how to modify it for sorting a file, based on one of the record fields. Be very careful to follow the code syntax when "adapting" this code. Batch code syntax is VERY complicated when using arrays inside of FOR loops.
NOTE: The code in this listing has been MODIFIED from that previously presented here. The video for the Bubblesort has NOT been modified to incorporate the changes. In the modified code and test driver, the first and last indices of the array to be sorted are passed to the sort routine, and the array is SHARED between the test and sort code. The array name is NOT passed as a parameter.
How to copy the function and test driver code from my web page was described in the previous video "String Input Function".
Background: What is a "bubble" sort, and why use it? While sorting, items "bubble" through the list until they reach their final position. It's one of the easiest sorts to program, and it works perfectly well for sorting 100 or less items using batch code. Unfortunately, it's an N**2 sort. That means if you increase the number of items 10 times, the sort time goes up 100 times. On my (fairly fast) computer, it sorts 100 items in 9-1/2 seconds. (1000 items would take about 1000 secs (17 min.) For large lists, use a quicksort, which is an N log N sort. Sorts that would take several hours with a bubble sort, take a few seconds with a quicksort. Quicksort is much harder to program.
First, a reminder. Batch code doesn't really have arrays, but we can pretend it does. Actually x[1], x[2], x[3] aren't elements in an array, like they are in other programming languages; the letters, [], and digits are part of the NAME of each variable.
First, I'll show an internal sort function with its test driver in a single batch file without description. Then I'll show and describe an external sort function in a separate batch file. In my tests, both sorts sorted 100 random numbers in 9-1/2 seconds.

Test driver, with an INTERNAL sort function:
@ECHO off
setlocal enabledelayedexpansion
ECHO before sort
set last1=100
SET last=%last1%
For /l %%i in (1,1,%last%) do (
set/a x[%%i]=!random! * 100/ 32768 + 1
REM set/a x[%%i]=%last1%+1-%%i
echo %%i !x[%%i]!
)
REM sort the array
ECHO please wait until sort completes
echo Start:%time%
call:SORTIT last1,x
ECHO.
:done
Echo end:%time%
For /l %%i in (1,1,%last1%) do echo %%i !x[%%i]!
pause
GOTO:eof

:SORTIT
SET last=!%1!
SET x=%2
:SORT1
SET/a last=%last% - 1
set moved=no
For /l %%i in (1,1,%last%) do (
set/a j=%%i+1
call set ta=%%x[%%i]%%
Call set tb=%%x[!j!]%%
IF !ta! GTR !tb! (
set x[%%i]=!tb!
set x[!j!]=!ta!
set moved=yes
)
)
if "!moved!"=="no" GOTO done1
IF %last% GTR 1 GOTO SORT1
:done1
echo 1
GOTO:eof

Test driver using an EXTERNAL sort function.
This code has been modified from that previously presented here. The start index is now passed as a parameter, and the array is SHARED, not passed as a parameter.

@ECHO off
setlocal enabledelayedexpansion
SET first1=1
set last1=10
SET last=%last1%
ECHO begin bubble sort-- please wait for completion
ECHO begin bubble sort of %last1% items -- array before sort > temp.txt
For /l %%i in (1,1,%last%) do (
set/a x[%%i]=!random! * 100/ 32768 + 1
REM set/a x[%%i]=%last1%+1-%%i
echo %%i !x[%%i]! >> temp.txt
)
REM sort the array
ECHO please wait until sort completes
echo Start:%time% >> temp.txt
call SORTIT first1 last1
ECHO.
:done
ECHO sort complete -- results in temp.txxt
Echo end:%time% >> temp.txt
ECHO end bubble sort of %last1% items -- array after sort >> temp.txt
For /l %%i in (1,1,%last1%) do echo %%i !x[%%i]! >> temp.txt
pause
GOTO:eof

External (modified) sort function:This code has been modified from that previously presented here. This code has been modified from that previously presented here. The start index is now passed as a parameter, and the array is SHARED, not passed as a parameter.

:SORTIT
SET first2=!%1!
SET last2=!%2!
If %first2% GEQ %last2% GOTO:eof
SET last=%last2%
:SORT1
SET/a last=%last% - 1
set moved=no
For /l %%i in (%first2%,1,%last%) do (
set/a j=%%i+1
set ta=!x[%%i]!
Call set tb=%%x[!j!]%%
IF !ta! GTR !tb! (
set x[%%i]=!tb!
set x[!j!]=!ta!
REM Echo moved
set moved=yes
)
)
if "!moved!"=="no" GOTO done1
IF %last% GTR %first2% GOTO SORT1
:done1
GOTO:eof

Create & Execute Windows Command Files -
Quicksort Function

This video shows a "quick sort" written in batch code. The "bubble" sort was described in a previous video. That sort was simple to program, but, as mentioned in that video, is very slow for large lists. The "quicksort" is much harder to program, especially in batch code, but is MUCH faster than the bubble sort. Did I mention it's MUCH faster?

My tests (I have a fairly fast computer, running Windows 10 Pro):

Sort Times For Bubblesort VS Quicksort
No. Items
Bubblesort
Quicksort
10
.06 sec

.06 sec

100
5.5 sec
1.5 sec
1000
9.5 min
25 sec
10000
15.8 hr (calculated)
10.7 min

And YES, the numbers have been checked several times. The literature states that the bubble sort time varies as N**2, where N is the no. items sorted, while the quicksort time varies as N log N, which goes up MUCH SLOWER than N**2. The quicksort is MUCH harder to program (or to modify from my code), as will be shown in the code walkthru.
Quicksort works by dividing the original list into smaller and smaller non-overlapping segments. When a segment becomes smaller than the program limit (I use 10), the bubble sort is used to sort the segment.
Programming note: Only the test program uses the setlocal statement to enable delayed expansion. The quicksort and bubble sort functions called from the test program DO NOT contain the setlocal statement. This enables the same array to be accessed from the test and sort functions, and delayed expansion can be used in all the files. The bubble sort described in a previous video has been modified so that only the start and end indices in the array are specified, and the array name is not passed as a parameter. (The code has been modified in the Bubblesort listing on my website.) Be very careful to follow the code syntax when "adapting" this code. Batch code syntax is VERY complicated when using arrays inside of FOR loops.
How to copy the function and test driver code from my web page was described in the previous video "String Input Function".
The external bubble sort function and it's driver in the previous script have been modified in that script.

Test driver (output goes to file temp.txt):
@ECHO off
setlocal enabledelayedexpansion
set first1=1
SET last1=100
ECHO begin quicksort -- please wait for completion
ECHO begin quicksort -- array before sort > temp.txt
set first=0
ECHO All output is directed to file temp.txt
Echo before sort of %last1% items > temp.txt
REM fill array with random numbers
For /l %%i in (%first1%,1,%last1%) do (
set/a x[%%i]=!random! * !last1!/ 32768 + 1
REM set/a x[%%i]=%last1%+1-%%i
echo %%i !x[%%i]! >> temp.txt
)
REM sort the array
echo Start:%time% >> temp.txt
echo Start:%time%
call quicksort first1 last1
ECHO.
:done
Echo end:%time%
ECHO sort complete -- results in temp.txt
Echo end:%time% >> temp.txt
FOR /l %%i in (%first1%,1,%last1%) DO (
ECHO %%i !x[%%i]! >> temp.txt
)
pause
GOTO:eof

The modified sort function is called by the quicksort function.
:SORTIT
SET first2=!%1!
SET last2=!%2!
REM ECHO sortit2 f2 l2 %first2% %last2% >> temp.txt
IF %first2% GEQ %last2% GOTO done5
SET last=!last2!
REM ECHO before bubble sort f %first2% l %last2% >> temp.txt
REM FOR /l %%i in (%first2%,1,%last2%) DO ECHO %%i !x[%%i]! >> temp.txt
:SORT3
SET/a last=!last! - 1
REM ECHO 1 last %last% >> temp.txt
set moved=no
For /l %%i in (%first2%,1,%last%) do (
set/a j=%%i+1
set ta=!x[%%i]!
Call set tb=%%x[!j!]%%
IF !ta! GTR !tb! (
set x[%%i]=!tb!
set x[!j!]=!ta!
REM Echo moved
set moved=yes
)
)
REM echo moved !moved!
if "!moved!"=="no" GOTO done5
IF %last% GTR %first2% GOTO SORT3
:done5
REM ECHO after bubble sort >> temp.txt
REM FOR /l %%i in (%first2%,1,%last2%) DO ECHO %%i !x[%%i]! >> temp.txt
GOTO:eof

Quicksort function:
REM parms %1 - start, %2 - end
REM ECHO quicksort >> temp.txt
SET plim=10
SET pindex=1
Set startp=!%1!
SET endp=!%2!
REM echo qs2 s %startp% e %endp% >> temp.txt
IF %startp%==%endp% GOTO done
SET/A tcount=%endp%-%startp% + 1
REM ECHO tc %tcount% >> temp.txt
IF %tcount% LEQ %plim% (
CALL sortit startp endp
GOTO done
)
SET twpartf[%pindex%]=%startp%
SET twpartl[%pindex%]=%endp%
:nextpart
IF %pindex%==0 GOTO done
REM fetch partition boundaries
SET pstart=!twpartf[%pindex%]!
SET pend=!twpartl[%pindex%]!
REM ECHO start part %pstart% to %pend% >> temp.txt
REM ECHO before part >> temp.txt
SET dflag=no
SET/A pindex=%pindex%-1
SET tf=!pstart!
SET tl=!pend!
CALL SET xf=%%x[!tf!]%%
CALL SET xl=%%x[!tl!]%%
REM ECHO pre-partition
:SORT1
:declast
if !xf! LEQ !xl! (
SET/a tl=!tl!-1
IF !tl! == !tf! goto endpass
CALL SET xl=%%x[!tl!]%%
GOTO declast
)
REM interchange the items
SET x[!tl!]=!xf!
SET x[!tf!]=!xl!
SET/A tf=!tf!+1
IF !tf!==!tl! goto endpass
SET xl=!xf!
call SET xf=%%x[!tf!]%%
:incfirst
IF !xl! GEQ !xf! (
SET/A tf=!tf!+1
IF !tf!== !tl! goto endpass
call set xf=%%x[!tf!]%%
GOTO incfirst
)
SET x[!tl!]=!xf!
SET x[!tf!]=!xl!
SET/A tl=!tl!-1
IF !tf!==!tl! goto endpass
SET xf=!xl!
call SET xl=%%x[!tl!]%%
GOTO declast
:endpass

REM bubble sort small partition, stack larger partitions
SET/A twlen=!tf!-%pstart% + 1
REM ECHO len1 !twlen! plim !plim! >> temp.txt
IF !twlen! LEQ !plim! (
SET/A tff=!tf!-1
CALL sortit pstart tff
) else (
REM ECHO part 1 tf !tf! >> temp.txt
SET/A tff=!tf!-1
REM ECHO tff !tff! >> temp.txt
REM FOR /l %%i in (!pstart!,1,!tff!) DO ECHO %%i !x[%%i]! >> temp.txt
SET/A pindex=!pindex!+1
SET twpartf[!pindex!]=%pstart%
SET twpartl[!pindex!]=!tff!
)
SET/A twlen=%pend%-!tf! + 1
REM ECHO len2 !twlen! plim !plim! >> temp.txt
IF !twlen! LEQ !plim! (
SET/A tff=!tf!+1
CALL sortit tff pend
) else (
REM ECHO part 2 tf !tf! >> temp.txt
SET/A tff=!tf!+1
REM Echo tff !tff! >> temp.txt
REM FOR /l %%i in (!tff!,1,!pend!) DO ECHO %%i !x[%%i]! >> temp.txt
SET/A pindex=!pindex!+1
SET twpartf[!pindex!]=!tff!
SET twpartl[!pindex!]=%pend%
)
REM ECHO after stack or sort >> temp.txt
GOTO nextpart
:done
GOTO:eof

Create & Execute Windows Command Files -
Quicksort For Text Files Summary

This video shows how to sort a comma-separated text file, or CSV file, using the quicksort algorithm written in WIndows Batch code. The video demonstrates how to export gmail contacts to a .csv file, pre-process the file with the notepad editor, then sort the file. The next video "File Sort Code Walkthru" gives a comprehensive description of the code in the quicksort file sort package. This function sorts 75 records in 6.3 secs, and 700 records in 4 min.

The sort function described in this video may not exactly fill your needs, but the walkthru in the next video will give you many useful functions you can adapt for your own use, and will point out some pitfalls to avoid when coding in batch.

The code used to sort the file includes these batch files: test file, quicksort, bubble sort, and several functions to analyze and manipulate arrays, text strings or numbers.
The bubble sort and quicksort functions described in this video have been modified from those in video "Quicksort Function". The quicksort has been altered so that it is a "stable" sort, and so that it can be used for multi-column sorts. (Show the SETS) The sorted file is is output into two files, (show temp.txt) one displaying summary data for the sort, and a formatted listing of the sorted file, showing the last token sorted, and the complete record. (show censored, edited file again) The other file is the same format as the original file, with the records sorted according to the user's request.

 

I've censored snapshots of my contacts list used for this video. Video "Censoring A Photo" in playlist "How To Record Videos" shows how to do this, using Adobe Photoshop Elements. Playlist: https://www.youtube.com/playlist?list=PLgHiYdbb2tMIQkEQXls8bvaPsLTDQrNFx
If you are using a desktop or laptop, there's a clickable link to the playlist below the video window. There are also links to my youtube channel, and to my website.
Youtube channel: https://www.youtube.com/user/tomstda
My Website: http://www.tomstechnotes.com
Script for this video (contains the code): http://webpages.charter.net/tomspage/TTNSite/batfiles.html

 

Steps required to sort the contacts file. They are shown in this video.

Some "tweeks" must be made to the exported contacts list to sort it correctly. I'll show you how to fix them with the editor. Lastly, if you've automatically added contacts from sent emails, those contacts are missing their first and last namesSimple solution to missing first names: don't export "all contacts".

Some "tweeking" of the file is required before it will sort correctly. I use the notepad editor, and I'll demonstrate with a dummy file. SHOW DUMMY FILE

Adjacent commas are treated as a single comma when separating record fields. Select edit replace comma comma with comma space comma. Do the replace twice. Ampersands in fields being sorted (such as the first name field) cause strange program behaviot. Replace all ampersands (if you use them) with a left bracket "[", or some other character that does NOT appear in the contacts list. Contacts missing their first name will cause all record fields to be shifted to the left when reading the record. Manually insert a single space before the first comma. The program will insert "none" in all missing fields that are sorted (except for the first name field.)

Example using a dummy file.

This video illustrates a LOT of coding techniques. The code walkthru will help you incorporate many specialized "snippets" into your own programs.
I don't pretend to be an expert in batch coding. My technique is:
google to get a fuzzy idea of how to code something I need
Play with the syntax (lots of echo and pause statements)until I get it to work in my program. I tend to use delayed expansion many times when I don't really need it. (and maybe CALL SET, when SET would work. But using it when you dont't have to is MUCH better than NOT using it when you DO HAVE TO!
Warning: some of the functions do NOT include a setlocal statement. If you use those, either modify them to add the setlocal, or be VERY careful not to use variable names that duplicate those in the function.
The code assumes the file to be sorted is in the same directory as the sort functions.

Features of the program.

Four variables are set to customize the sort.
file 1 - file to be sorted
file2 - destination file.
tokens - list of columns to be sorted, separated by spaces.
headerrecs - no. of header records in the file. Header records are displayed, but not sorted.

The file is read into internal arrays, the file is sorted on the specified columns using the quicksort algorithm, then output to a text file.

Note: The test driver (only) has been purged of unnecessary delayed expansion usage. Other functions may contain some unneeded delayed expansions.

Test driver -- store with any name.bat
@ECHO off
setlocal enabledelayedexpansion
ECHO Sort program executed from file %~n0
ECHO Sort program executed from file %~n0 > temp.txt
REM prepare array of tokens
SET file1=contactsalledited.csv
SET file2=temp2.txt
SET tokens=3
SET headerrecs=1
FOR %%i in (%tokens%) DO (
SET/A tokencnt+=1
SET tokenl[!tokencnt!]=%%i
)
Set skip=
SET tokennum=0
:nexttoken
SET/A tokennum+=1
CALL SET token=%%tokenl[%tokennum%]%%
ECHO tokennum %tokennum% token %token%
IF %tokennum%==1 (
echo read full recs from file %file1% into array y >> temp.txt
SET first=0
FOR /f "%skip% delims=" %%i in (%file1%) do (
SET/A first=!first!+1
SET y[!first!]=%%i
)
set LAST1=!first!
ECHO File %file1% contains !last1! records >> temp.txt
ECHO File %file1% contains !last1! records
SET/A first1=%headerrecs%+1!
)
REM fill array x with tokens to be sorted
REM echo skip %skip% tokens %tokennum% file1 %file1% >> temp.txt
REM echo skip %skip% tokens %tokennum% file1 %file1%
SET first=0
ECHO read column %token% from file %file1%
ECHO read column %token% from file %file1% >> temp.txt
FOR /f "%skip% tokens=%token% delims=," %%i in (%file1%) do (
SET/A first+=1
IF "%%i"==" " (
SET x[!first!]=empty
) ELSE SET x[!first!]=%%i
REM echo %%i
)
REM reset i/o file for subsequent token read, sort file output
REM Echo before sort tokennum !tokennum! >> temp.txt
REM Echo before pass !sortpass! of 2-pass sort >> temp.txt
REM )
REM FOR /l %%i in (%first1%,1,!last1!) DO (
REM ECHO %%i !x[%%i]! !y[%%i]! >> temp.txt
REM )
REM sort the array
echo Start sort column %token% at time:%time%
echo Start sort column %token% at time:%time% >> temp.txt
call quicksortstable first1 last1
echo end sort column %token% at time:%time%
echo end sort column %token% at time:%time% >> temp.txt
echo writing sorted file to %file1%
set file1=%file2%
type nul > %file1%
FOR /l %%i in (1,1,%last1%) DO ECHO !y[%%i]! >> !file1!
IF %tokennum% LSS %tokencnt% GOTO nexttoken
REM ECHO process after final sort
REM echo AFTER PAD first1 %first1% last1 %last1% >> temp.txt
REM calc col width for rec numbers
CALL num_digits %last1% colwid
REM ECHO last1 !last1! colwid %colwid% >> temp.txt
REM determine longest string in the token array, adjust for removed nums
CALL strlen x last1 max_len
SET/A max_len=%max_len%-%colwid%
ECHO maxlen !max_len! colwid %colwid% >> temp.txt
REM ECHO pad len for token col %max_len% >> temp.txt
ECHO Final Sort Listing >> temp.txt
FOR /l %%i in (1,1,%last1%) DO (
SET ty=%%i
Call pad_string ty %colwid% tyout
REM remove concatenated rec number before final display
SET txouttt=!x[%%i]!
CALL set txoutt=%%txouttt:~0,-%colwid%%%
call pad_string txoutt %max_len% txout
ECHO !tyout! !txout! !y[%%i]! >> temp.txt
)
Echo End processing for column(s) %tokens% at time:%time%
Echo End processing for column(s) %tokens%:%time% at time>> temp.txt
pause
GOTO:eof

Store this bubblesort as sortit2.bat
:SORTIT
SET first2=!%1!
SET last2=!%2!
REM ECHO sortit2 f2 l2 %first2% %last2% >> temp.txt
IF %first2% GEQ %last2% GOTO done5
SET last=!last2!
REM ECHO before bubble sort f %first2% l %last2% >> temp.txt
REM FOR /l %%i in (%first2%,1,%last2%) DO ECHO %%i !x[%%i]! !y[%%i]! >> temp.txt
:SORT3
SET/a last=!last! - 1
REM ECHO 1 last %last% >> temp.txt
set moved=no
For /l %%i in (%first2%,1,%last%) do (
set/a j=%%i+1
set ta=!x[%%i]!
SET tay=!y[%%i]!
Call set tb=%%x[!j!]%%
CALL set tby=%%y[!j!]%%
IF !ta! GTR !tb! (
set x[%%i]=!tb!
set x[!j!]=!ta!
SET y[%%i]=!tby!
SET y[!j!]=!tay!
REM Echo moved
set moved=yes
)
)
REM echo moved !moved!
if "!moved!"=="no" GOTO done5
IF %last% GTR %first2% GOTO SORT3
:done5
REM ECHO after bubble sort >> temp.txt
REM FOR /l %%i in (%first2%,1,%last2%) DO ECHO %%i !x[%%i]! !y[%%i]! >> temp.txt
GOTO:eof

Quicksort function -- store this function as quicksortstable.bat
REM parms %1 - start, %2 - end
Set startp=!%1!
SET endp=!%2!
REM concatenate the rec no. to the token array to stabilize the sort
REM SET max_len=4
SET plim=10
SET pindex=1
CALL num_digits !endp! max_len
FOR /l %%i in (%startp%,1,%endp%) DO (
CALL SET xf=%%x[%%i]%%
set temp1=%%i
CALL pad_numeric temp1 !max_len! temp
SET x[%%i]=!xf!!temp!
REM ECHO padded num before !temp1! after !temp!
)

REM echo qs %startp% %endp% >> temp.txt
REM IF %startp%==%endp% GOTO done
SET/A tcount = %endp%-%startp%+1
IF %tcount% LEQ %plim% (
CALL sortit2 startp endp
GOTO done
)
SET twpartf[%pindex%]=%startp%
SET twpartl[%pindex%]=%endp%
:nextpart
IF %pindex%==0 GOTO done
REM fetch partition boundaries
SET pstart=!twpartf[%pindex%]!
SET pend=!twpartl[%pindex%]!
REM ECHO start part %pstart% to %pend% >> temp.txt
REM ECHO before part >> temp.txt
SET dflag=no
SET/A pindex=%pindex%-1
SET tf=!pstart!
SET tl=!pend!
CALL SET xf=%%x[!tf!]%%
CALL SET yf=%%y[!tf!]%%
CALL SET xl=%%x[!tl!]%%
CALL SET yl=%%y[!tl!]%%
REM ECHO pre-partition
:SORT1
:declast
if !xf! LEQ !xl! (
SET/a tl=!tl!-1
IF !tl! == !tf! goto endpass
CALL SET xl=%%x[!tl!]%%
CALL SET yl=%%y[!tl!]%%
GOTO declast
)
REM interchange the items
SET x[!tl!]=!xf!
SET y[!tl!]=!yf!
SET x[!tf!]=!xl!
SET y[!tf!]=!yl!
SET/A tf=!tf!+1
IF !tf!==!tl! goto endpass
SET xl=!xf!
SET yl=!yf!
call SET xf=%%x[!tf!]%%
CALL set yf=%%y[!tf!]%%
:incfirst
IF !xl! GEQ !xf! (
SET/A tf=!tf!+1
IF !tf!== !tl! goto endpass
call set xf=%%x[!tf!]%%
call set yf=%%y[!tf!]%%
GOTO incfirst
)
SET x[!tl!]=!xf!
SET x[!tf!]=!xl!
SET y[!tl!]=!yf!
SET y[!tf!]=!yl!
SET/A tl=!tl!-1
IF !tf!==!tl! goto endpass
SET xf=!xl!
SET yf=!yl!
call SET xl=%%x[!tl!]%%
call SET yl=%%y[!tl!]%%
GOTO declast
:endpass

REM bubble sort small partition, stack larger partitions
SET/A twlen=!tf!-%pstart% + 1
REM ECHO len1 !twlen! plim !plim! >> temp.txt
IF !twlen! LEQ !plim! (
SET/A tff=!tf!-1
CALL sortit2 pstart tff
) else (
REM ECHO part 1 tf !tf! >> temp.txt
SET/A tff=!tf!-1
REM ECHO tff !tff! >> temp.txt
REM FOR /l %%i in (!pstart!,1,!tff!) DO ECHO %%i !x[%%i]! !y[%%i]! >> temp.txt
SET/A pindex=!pindex!+1
SET twpartf[!pindex!]=%pstart%
SET twpartl[!pindex!]=!tff!
)
SET/A twlen=%pend%-!tf! + 1
REM ECHO len2 !twlen! plim !plim! >> temp.txt
IF !twlen! LEQ !plim! (
SET/A tff=!tf!+1
CALL sortit2 tff pend
) else (
REM ECHO part 2 tf !tf! >> temp.txt
SET/A tff=!tf!+1
REM Echo tff !tff! >> temp.txt
REM FOR /l %%i in (!tff!,1,!pend!) DO ECHO %%i !x[%%i]! !y[%%i]! >> temp.txt
SET/A pindex=!pindex!+1
SET twpartf[!pindex!]=!tff!
SET twpartl[!pindex!]=%pend%
)
REM ECHO after stack or sort >> temp.txt
GOTO nextpart
:done
GOTO:eof

Store as num_digits.bat
REM function to determine number of digits in a number
:numdigits
setlocal enabledelayedexpansion
SET temp=%1
:loop
SET/A temp=%temp% / 10
SET/A count+=1
IF %temp% GTR 0 GOTO loop
endlocal & SET %2=%count%
GOTO:eof

Store as pad_numeric
REM Pads numbers on the left with zeros
@echo off
REM pad/truncate string
REM parms: 1 - in string, 2 - pad length, 3 - out string
set strin=!%1!
set padlen=%2
REM ECHO pad_numeric strin !strin! padlen !padlen!
REM IF not "!padlen!"=="" set padlen=!%2!
call :strlenn strin strlen
REM echo STRLEN PADLEN %STRLEN% !PADLEN!
IF !strlen! GTR %padlen% (
SET strout=!strin:~0,%padlen%!
goto DONE
)
SET strout=%strin%
REM ECHO in out x%strin%x x%strout%x
SET/a padlen=%padlen%-1
REM ECHO strlen padlen %strlen% %padlen%
FOR /L %%i in (%strlen%,1,!padlen!) do (
SET strout=0!strout!
)
:DONE
REM Echo x!strin!x x!strout!x
SET %3=%strout%
GOTO:eof

SETLOCAL enabledelayedexpansion
:strLenn
SET len=0
:strLen_Loop
if not "!%1:~%len%!"=="" set /A len+=1 & goto :strLen_Loop
ENDLOCAL & set %2=%len%
goto:eof

Store as pad_string.bat
REM pads strings on the right with spaces
@echo off
REM pad/truncate string to specified length
REM parms: 1 - in string, 2 - pad length, 3 - out string
set strin=!%1!
set padlen=%2

REM echo in pad_string string !strin! padlen !padlen! >> temp.txt
call :strlenn strin strlen
REM echo in pad_string strlen !strlen! >> temp.txt

IF !strlen! GTR !padlen! (
SET strout=!strin:~0,!padlen!
goto DONE
)
SET strout=!strin!
REM ECHO in out x%strin%x x%strout%x
SET/a padlen=!padlen!-1
REM ECHO strlen padlen %strlen% %padlen%
FOR /L %%i in (!strlen!,1,!padlen!) do (
SET strout=!strout!
)
:DONE
REM Echo x!strin!x x!strout!x
SET %3=!strout!
GOTO:eof

:strLenn
setlocal enabledelayedexpansion
SET len=0
:strLen_Loop
if not "!%1:~%len%!"=="" set /A len+=1 & goto :strLen_Loop
(endlocal & set %2=%len%)
goto:eof

Store as strlen.bat
REM determines max string length in an array of strings
@echo off
setlocal enabledelayedexpansion
REM %1 - array
REM %2 - length of array
REM %3 - max len
SET array_len=!%2!
REM echo array_len !array_len!
SET IX=0
set strlmax=0
FOR /L %%I IN (1,1,!array_len!) DO (
SET/A IX=!IX!+1
call :strLennn %1[!IX!] strlenn
REM echo strlenn !strlenn!
if !strlenn! gtr !strlmax! set strlmax=!strlenn!
REM echo String is !strlenn! characters long max !strlmax!
)
REM echo final value is !strlmax!
(ENDLOCAL
set %3=%strlmax%
)
goto:eof

:strLennn
setlocal enabledelayedexpansion
SET len=0
:strLen_Loop
if not "!%1:~%len%!"=="" set /A len+=1 & goto :strLen_Loop
(endlocal
set %2=%len%
)
goto :eof

Create & Execute Windows Command Files -
File Sort Code Walkthru

This video gives a detailed code walkthru for the Quicksort package shown in video "Quicksort For Text Files Summary". You should watch that video before watching this one.

The sort function described in this video may not exactly fill your needs, but the walkthru in the next video will give you many useful functions you can adapt for your own use, and will point out some pitfalls to avoid when coding in batch.

The code for the File sort is in the script for "Create & Execute Windows Command Files - Quicksort For Text Files Summary

 

Share by: