User Tools

Site Tools


ops102:windows_scripting

Windows Scripting

Windws vs. Linux Scripting

Windows shell scripting is similar to Linux shell scripting in many ways.

However, since Windows and Linux (and other Unix-like operating systems) have different technical heritages, some of the syntax and approaches are very different.

An Abundance of Shells

We've looked at scripting on Linux systems using the bash shell – which is the most widely-deployed shell on Linux and other Unix-like systems. There are many other shells on similar systems, including:​

  • sh – the original Unix shell (“Bourne Shell”), written by Steven Bourne​
  • ksh – the Korn shell, written by David Korn​
  • csh – the C shell, which has a C-like syntax​
  • fish – the Friendly Interactive shell​
  • Zsh – the Z shell, similar to ksh​

Many of these have a syntax based on and similar to the original Bourne shell, which is standardized in the POSIX.1 standard (or IEEE Standard 1003.1), and these shells have a lot in common.​

On Windows, there are two main shells:

  • CMD - The Windows command shell, which is the traditional Windows shell. Although based on traditional DOS command syntax, the CMD shell has been considerably expanded, with many new features added over the last few years.​
  • PowerShell – this is a new Windows command shell, which combines scripting with object-oriented programming. It is pre-installed for interactive use on current Windows systems; however, the execution of PowerShell scripts is disabled by default on all Windows “client” (non-server) systems, including Seneca lab computers.​

​ Due to PowerShell scripting being disabled by default, and because object oriented programming is not taught in the first semester programming courses, we will focus on scripting using the traditional Windows CMD shell.​

Cross-Platform Scripting

There are several possible approaches to writing scripts that will work on both Linux and Windows systems, as well as other common operating systems such as Mac OS:​

  • Bash or Zsh – bash is the default shell on most Linux systems, and zsh is the default shell on most Mac OS systems; either shell can be easily used on either system. Both shells are available as third-party add-ons for the Windows operating system, usually shipped with a collection of GNU utilities compiled for use with Windows (for example, see https://gitforwindows.org/)​
  • PowerShell – installed by default on current Windows systems, it is also available for Linux and Mac OS systems, although it is not commonly used on those systems yet (see https://github.com/PowerShell/PowerShell)​

Other Interpreted Languages

In addition to shell scripting languages, there are other interpreted languages that are well suited for cross-platform development, including Python and Perl.​

​When should you use a shell scripting langauge?​

  • Shell scripting languages are ideally suited for process control – executing, managing, and combining external programs to accomplish tasks.​
  • Shell scripting languages are not well-suited for implementing advanced processing algorithms, because they generally lack features such as good floating-point support, typed variables, and strong support for large arrays and hashes.​

Windows "Shell Scripts" vs. Batch Files"

DOS and early Windows systems were inherently interactive in nature, and early scripts were called “batch files” because they were viewed as similar to non-interactive batch processing on mainframe systems.​

This terminology has stuck, and Windows shell scripts are still often called “batch files” (hence the occasional use of the .bat extension instead of .cmd).​​

The concept of a “batch file” and a “shell script” are roughly equivalent.​

Basic Requirements for Shell Scripts

Remember these requirements? They apply to Windows scripts too:

1. Create a text file containing shell commands.​ Use any text editor, such as Notepad, to create the file.

2. Tell the operating system which shell to use to execute the commands.​ In Windows, the filename extension is used to associate a file with a program, and this mechanism is used to associate a script with a command interpreter.​ ​

  • For CMD scripts, the extension “.cmd” is used.​ For historical reasons, the extension “.bat” is also accepted.​
  • For PowerShell scripts, the extension “.ps1” is used.​ The reason that “.ps” isn't used is that that extension was already used for PostScript files.​ (As a reminder: We're not going to write PowerShell scripts in this course).​

3. Ensure that the script file has the appropriate permissions.​ On Windows, the ability to read the script file is sufficient (and this is the default permission, so no change is usually required for scripts that you create for your own use; the situation may be different for scripts that are shared to other machines over the network or to other users on your system).​

Command Echos​

Windows defaults to displaying each command in a script before executing it (the opposite of the default in the bash shell). If you do not want each command to be displayed, you can:​

  • Add an @ sign in front of each command, or​
  • Issue the echo off command.​

Usually, you'll combine these in a script, using this as one of the first lines:​

@echo off​

A Basic Script Example

Here is a simple example script using two commands, echo and date:

@echo off
echo The current date is:
date /t

If this is save into the file named “now”, the permission could be set with this command:

$ chmod u+rx now

The script can then be executed. Normally, the current working directory is not searched, so to run the a script in the current directory, you will need to explicitly specify the directory name like this:

$ ./now
The current date is:
2024-12-11

Variables

Setting a Variable

To set a variable, use the set keyword with a variable name, an equal sign, and the variable value:

set A=5
set B=World

If the variable does not exist, it will be created. If it does exist, the previous value will be discarded.

Variable names may contain letters, digits, or underscores, but must not start with a digit. Case does not matter! The variable names Number, number, and NUMBER all refer to the same variable.

Do not put spaces on either side of the equal sign.

Variables are not typed – they may be used as strings, integers, or decimal values.

Accessing a Variable

To access a variable, place a percent sign [%] on either side of it, and use it in a command as an argument (or as a command name):

> SET B=World
> echo %B%
World
> echo Hello $B
Hello World

Quoting

Word Splitting and Quoting

Quoting in the Windows shell is very different from Bash!

Using single or double quotes causes the quotes themselves to be included as part of the string or argument in most cases, but not when dealing with a filename:​

 > ECHO "Hello"​
 "Hello"​

 > ECHO test > "test file"​

​ Quoting is not required when assigning a string value which contains spaces to a variable:

> SET A=One Two Three
> ECHO %A%
One Two Three

Carat Symbols

Escaping characters to remove their special meaning is performed using the carat [^] symbol in Windows.​ In this example, the ampersand [&] symbol would normally cause an error, but it can be treated as a regular character by escaping it with a carat:

> echo Lost ^& Found
Lost & Found

When piping, a CMD subshell is started for each command in the pipeline, and it is necessary to use triple carat symbols ^^^ to escape characters:​

> echo Lost ^^^& Found | find "Lost" ​
Lost & Found ​

Environment Variables

By default, all variables are environment variables, inherited by child processes.​​

Environment variables are commonly used to pass configuration information to programs and to configure how programs operate.​

You can view all of the current variables with the set command; you'll probably want to pipe the output through more. ​ Environment variables are used by all processes, not just the shell!​

Common Environment Variables

Environment Variable Purpose Examples
CD Current directory ECHO %CD%
TIME Current time (HH:MM:SS) ECHO %TIME%
DATE Current date in local format ECHO %DATE%
ERRORLEVEL The error code / exit status of the last command executed (note that some commands or programs do not set this variable as expected). DIR \FileThatDoesNotExist
ECHO %ERRORLEVEL%
PATH A semicolon [;] separated list of directories that will be searched when looking for a command
PROMPT The prompt presented by the shell. SET PROMPT=Enter a command:
SET PROMPT=$P$G
RANDOM A random integer (0-32767) ECHO %RANDOM%

Note that the prompt and path programs may also be used to adjust the PROMPT and PATH environment variables, respectively.

Reading Variable Values from STDIN: SET /P

You can read values from standard input (stdin) and assign them to a variable with the set command using the /p option (aka switch). When you do this, the value specified on the right-hand side of the equal sign is used as the prompt presented to the user:

> set /p NAME=Enter your name:
Enter your name: J. Doe

> echo %NAME%
J. Doe

Here is a script which uses a couple of SET /P statements:

@echo off​
set /p NAME=Please enter your name:​
echo Please to meet you, %NAME%​
set /p FILE=Please enter a filename:​
echo Saving your name into the file...​
echo NAME=%NAME% >> %FILE%​
echo Done.​

Command Capture

There is no direct equivalient to command capture, but it is possible to use SET /P with redirection from standard input using the less-than [<] symbol to capture one line of text:

> DATE /T >X
> SET /P D= <X
> ECHO %D%
2024-12-11

Arithmetic

CMD can perform integer arithmetic.

To evaluate an arithmetic expressions and store the results in a variable, use the SET command with the /A (arithmetic) option. (Note: when used interactively the result of the expressions evaluation will be output to stdout; this does not happen inside scripts).

> SET A=100
> SET B=12
> SET /A X=A*B
1200      <--- This does not get printed inside a script
> ECHO %X%
1200
> SET /A A+=1 > NUL:
> ECHO %A%
101
> SET /A C=A*B*2 > NUL:
> ECHO The answer is %C%
The answer is 2424

Notes:

  • You can perform more than one arithmetic evaluation and assignment in one SET command by separating the expressions with a comma [,]
  • Some characters used in arithmetic expressions, such as the carat symbol, may need to be quoted or escaped to function correctly.​
  • Percent signs, when used in arithmetic expressions (as the modulo operator), need to be doubled [%%] to avoid confusion with the percent signs placed around variable names​

Conditional Logic: IF/ELSE

The IF command takes a test, and uses the result of the test to control the execution of one or more commands. An ELSE clause is optional; if included, the first conditional commands should be placed in parenthesis.​

> set A=Blue                                       ​
> set B=Orange​
> set C=Blue​
​> if %A%==%C% echo Strings A and C match​
Strings A and C match​
> if %A%==%B% (echo Same!) else echo Different!​
Different!

Available Tests

There are four main types of tests available:

Tests Group 1: Filesystem Entries

Tests that a filename exists (regardless of the entry type: file or directory):

EXIST filename
Tests Group 2: String Equality

Test for string equality:

''string1''==''string2''
Tests Group 3: String and Numeric Comparisons

These tests accept two string arguments, both strings or both integers, which are compared. Adding the /i switch will make string comparisons case-insensitive (UPPER/lowercase).​

value1 EQU value2    True if the values are equal​
value1 NEQ value2    True if the values are not equal​
value1 LSS value2    True if the value1 less than value2 ​
value1 LEQ value2    True if the value1 less/equal to value2​
value1 GTR value2    True if the value1 less/equal to value2​
value1 GEQ value2    True if the value1 less/equal to value2​

To force a string comparison, enclose value1 and value2 in quotes. Otherwise, the shell will determine if the variables appear to contain integer values and compare them as integers, or otherwise compare them as strings.

Tests Group 4: Variable Definition, Errorlevel

Test to see if a variable is defined​: ​

DEFINED variable    True if variable is defined​

Test to see if the ERRORLEVEL is above a threshold​:

ERRORLEVEL value    True if ERORRLEVEL>=value​

Although it's probably better to just an integer comparison such as: %ERRORLEVEL% GEQ value​

Notes about IF and these Tests

  • These tests work only with the IF command
  • The IF command can be used with GOTO and a label:

IF test GOTO :skip​

...​
:skip​

Note that using a GOTO in a loop will make the shell forget about the loop, regardless of where the label is located!​

Negating and Combining Tests

You can negate (invert) a test with the NOT operator:

IF NOT EXIST %N% ECHO The file %N% does not exist.

Note that you cannot combine tests - there is no AND or OR operator.

Script Parameters

Arguments to a script are called parameters. You can access the parameters using the special variables %0, %1, %2, and so forth. %0 contains the name of the script, %1 contains the first parameter, %2 contains the second parameter, and so forth. Note that there is no second percent sign after the parameter number.

The shift command gets rid of the first parameter and shifts every parameter to a lower number.​

Examples:

> type params.cmd​
@echo off​
ECHO PARAM 0: %0​
ECHO PARAM 1: %1​
ECHO PARAM 2: %2​

> params red green blue​
PARAM 0: params​
PARAM 1: red​
PARAM 2: green​

> type params-shift.cmd​
@echo off​
ECHO List of all arguments: %*​
:start​
IF "%1"=="" GOTO :done​
ECHO %1​
SHIFT​
GOTO :start​
:done​

> params-shift yellow orange red​
List of all arguments: yellow orange red​
yellow​
orange​
red

The special variable %* returns all of the parameters.

On the command line, parameters may be separated by:

  • Space (or Tab)
  • Comma [,]
  • Semicolon [;]
  • Equal sign [=]

Looping

In the Windows CMD shell, looping is performed with the FOR statement.

Loops are controlled by an iterator variable, which has special rules:

  • The iterator variable name must be a single letter
  • The variable name is case sensitive
  • The variable name is written with a single preceeding percent sign [%] at all times when used from the command line, or double preceeding percent signs [%%] inside a script

Delayed Expansion

When the body of a FOR loop is executed, the variables are expanded (replaced by their values) before the loop begins. That means that any variables that are contained in the loop have their values locked-in and they can't be changed while the loop is executing.​

To allow updated variable values to be accessed within a loop:​

1, Set the EnableDelayedExpansion option:​

SETLOCAL EnableDelayedExpansion​

​ 2. Change any variables which will be updated during the execution of the loop by replacing the percent-signs ( % ) with exclaimation-marks ( ! ):​

%ERRORLEVEL%    ->    !ERRORLEVEL!​

Loop throush a List of Files or Parameters

To loop through a list of values such as filenames, use:

FOR    %variable IN (files) DO list​

The variable will be sequentially set to each of the given files values, and the loop body (list) will be executed once for each value.

The files value may be:

  • A list of filenames: FOR %F IN (file1.txt file2.pdf file3.c) DO ECHO %F
  • A filename pattern: FOR %F IN (*.pdf) DO ECHO %F
  • Fixed strings: FOR %C IN (Red Green Blue) DO ECHO %C
  • Or a list of all of the parameters: FOR %P IN (%*) DO ECHO %P

The /D option can be used along with a filename pattern to match only directories:

FOR /D %variable IN (files) DO list

Example

@echo off​ SETLOCAL EnableDelayedExpansion​ FOR F IN (*) DO (​ rem The CHOICE command presents a Y/N choice and sets %ERRORLEVEL% rem to 1 if the user selected Y and 2 if the user selected N CHOICE /M "DELETE F“​

IF !ERRORLEVEL!==1 (​
  ECHO ...Deleting %%F​
  DEL %%F​
) ELSE (​
  ECHO ...Skipping %%F​
)​

)

Loop through a Range of Integers

FOR /L (start, step, end) DO list

This type of loop counts forward or backwards from start to end by a given step.

Example:​ ​

@echo off​
rem Count from 0 to 5 in increments of 1​
FOR /L %%I IN (0,  1, 5) DO ECHO ... %%I ...​
 
rem Count from 4 to 0 in increments of -1​
FOR /L %%I IN (4, -1, 0) DO ECHO ... %%I ...

Output:

0
1
2
3
4
5   <- This is the end of output from the first loop, having gone from 0 to 5
4   <- The second loop starts output here, going from 4 to 0
3
2
1
0

Examples

Examples of using test: Integers vs Strings​

@echo off​
rem intcmp.cmd - compare as integers​
SET /A A=11,B=2​
IF %A% GTR %B% (​
  ECHO %A% is greater than %B%​
) ELSE ECHO %A% is less than or equal to %B%  ​
@echo off​
rem strcmp.cmd - compare as strings​
SET /A A=11,B=2​
IF "%A%" GTR "%B%" (​
  ECHO %A% is greater than %B%​
) ELSE ECHO %A% is less than or equal to %B%

Examples of using test: Integer Numbers​

@echo off​
SET /A COIN=%RANDOM% %% 2​
IF %COIN% EQU 0 (ECHO Heads!) ELSE ECHO Tails
ops102/windows_scripting.txt · Last modified: 2024/11/18 05:42 by chris

Donate Powered by PHP Valid HTML5 Valid CSS Driven by DokuWiki