Shell Variables
It is not uncommon to have a particular value that you’d like to use repeatedly during a shell session. Rather than constantly retyping this value, Command Prompt supports the creation of variables, which can be used to store information for the duration of a given session, or even to do simple arithmetic directly in the shell.
Generally speaking, variables are names or labels that you can create, and associate with some data. Then, when you want to place that data in a command at some later point, you can simply use the variable name as a stand-in. When the command is processed, the variable name will be replaced with the associated data.
The set
Command
Creating a variable is straightforward. You need to give Command Prompt a name for
the variable, and the value that you are assigning to it. For example, to create
a variable named my_var
with a value of this is a test
, you would use the
following command,
% set my_var=this is a test
Note here that the syntax is quite important. If you place a space to the right
of the equals sign, then the variable will actually take on the value of this is a test
, and if you place it to the left, then the variable name will become
my_var
. The odds are good that you don’t want either of those things, so
be sure to not add any spaces between the variable name, the equals sign,
and the beginning of the value.
Accessing the Values of a Variable
Let’s try using echo
to display the text that we assigned to our variable. Our
first idea might be to try,
% echo my_var
my_var
But, as you can see, this will only display the text my_var
, and not the data
associated with a variable of that name.
The problem is that, on a command line, you are just as likely to want to use
the text my_var
literally in a command (say, as a filename), as you are to
use it as a variable name, and so the shell will default to treating any text
literally. If you want to treat some text as a variable name, and ask the shell
to get its value, you need to add some special characters to tell it to do so.
On Command Prompt, this is done by using %
signs surrounding the name of the
variable you’d like to access. Thus, the command that we actually want to use
is,
% echo %my_var%
this is a test
There is nothing stopping you from accessing the value of a variable that you
did not define in advance using set
. There are some variables that are
pre-defined within your shell, called environment variables, but those will
be the topic of the next chapter. For now, let’s consider test_var
and assume
that you have not set it already, and that it isn’t pre-defined as part of your
shell’s environment.
In many programming languages, attempting to access an undefined variable will cause an error message to be displayed. However, shells are usually a little more lenient when it comes to such things. Running,
% echo %test_var%
%test_var%
we do not see any error message. Instead, we get the name of the variable, printed literally.
Note however that, even if accessing the variable doesn’t result in an error, the fact that the variable being accessed evaluates to something that you probably didn’t intend may cause some other part of your command to throw an error.
As an example, were we to run,
% move %test_var% my_file.txt
the shell will see the command exactly as you typed it, likely resulting in an
error due to %test_var%
not being the name of an existing file.
Performing Arithmetic
You can also use variables and the set
command to perform basic math on the
command prompt. The /a
flag to set
will cause it to evaluate mathematical
expressions given as arguments.
For example, we can add two numbers together like this,
% set /a 20+10
30
Note that the Command Prompt will display in the output buffer the result of the calculation. If you wanted to store the result in a variable, you could do that easily enough,
% set /a x=20+10
30
% echo %x%
30
Note that set
will still display the result, even when you assign it to
a variable.
The /a
option for set
supports the basic arithmetic operations of addition (+),
subtraction (-), multiplication (*), and division (/), as well as remainder
(%). However, it does not support floating point numbers. Floating point
numbers are numbers with a decimal point, like 3.14
or 1.0
. When doing
math with set
, everything is rounded down to the nearest integer. Thus, we
see things like,
% set /a 5 / 2
2
rather than the “correct” result of 2.5.
This is a pretty common limitation of shells, shared by bash (for example), so it’s worth getting used to. If you want to do math in a shell that requires floating point numbers, you’ll usually need to use an external calculator program (some exist with command line interfaces, so this isn’t as much of a limitation as it may seem at first).1
Finally, you can use variables inside of these arithmetic expressions. So you could do something like this,
% set x=5
% set y=9
% set z=2
% set /a t=(x+y)*z
28
Examples
Theoretically, that’s about all there is to simple variables: creating them and accessing their values. But it’s worth showing some examples of how these variables can be actually used.
In reality, variables are typically used in the context of scripting, where you place a sequence of commands in a file (called a batch file in the context of Command Prompt, or a shell script in most other contexts) to run together as a batch. In this context, there isn’t a user to type data into commands as needed, and so variables are a must. However, they do still have value in day-to-day interactive shell use.
Using Variables as Arguments Commands
As an example, let’s say we wanted to move a file to a new location, open it up in notepad to edit it, and then run it in a Python interpreter. The sequence of commands to do this might look like,
% move myfile.py mynewfile.py
% notepad mynewfile.py
% python mynewfile.py
However, if we were to tire of writing mynewfile.py
over and over again,
we could do something like this instead,
% set f=mynewfile.py
% move myfile.py %f%
% notepad %f%
% python %f%
We tell the shell that anytime we say %f%
, we actually mean mynewfile.py
,
using the set
command. After this, we can simply use our variable to refer to
the file, saving some typing.
You can also embed wildcards within a variable, and programs that accept wildcards will process them like normal. So if you wanted to move a bunch of python files from several directories into a new one, you could do something like this,
% set pyf=.\*.py
% set target=C:\users\douglas\documents\python
% cd dir1
% move %pyf% %target%
% cd ..\dir2
% move %pyf% %target%
% cd ..\dir3
% move %pyf% %target%
Note that we used an absolute path for the target directory; this is because we are using the same target pathname for commands in several directories, so we need to use an absolute path to ensure that all of the move commands are putting files in the same place.
We could actually have, in this specific case, gotten away with using
a relative pathname for the target variable. What relative pathname could
we have used that would have resulted in the same target for all three of
the move commands in the above example, assuming that the initial working
directory (before any cd
commands) was C:\users\douglas
?
See the answer
As C:\users\douglas
is the parent directory of the directories from which
we executed all three move instructions, we could use a relative path including
..
, namely
..\documents\python
Spaces in Variables
In our first example of the set
command, we included a space in the text of
our variable. Be careful with this when you are using variables to provide
arguments to commands, as the splitting up of the line into arguments occurs
after variable expansion. This means that if we were do to something
like this,
% set var=file with spaces.txt
% move %var% no-spaces.txt
the command that the shell processes will be,
% move file with spaces.txt no-spaces.txt
and your single variable will get split up into multiple seperate arguments.
To avoid this, you can place quotation marks around the variable in the command, like so,
% set var=file with spaces.txt
% move "%var%" no-spaces.txt
so that, after the value of the variable is substituted in, it will still be within quotation marks.
Technically, you could also do it this way,
% set var="file with spaces.txt"
% move %var% no-spaces.txt
putting the quotation marks into the variable definition. But Command Prompt behaves differently from most other shells in this regard, and so you should prefer to use quotes when you access variable, rather than when you set it, to develop good habits. And, as we’ll see in the next section, putting quotes in the definition on Command Prompt can also have some other implications with how you can use the variable.
Using Variables as Commands
Another interesting use of variables is that you can have the shell interpret their values as entire commands (with arguments). Going back to our earlier example of moving a bunch of Python files around, we could take advantage of this to further reduce our typing burden,
% set pyf=.\*.py
% set target=C:\users\douglas\documents\python
% set mcmd=move %pyf% %target%
% cd dir1
% %mcmd%
% cd ..\dir2
% %mcmd%
% cd ..\dir3
% %mcmd%
This works because the Command Prompt will first substitute all variables for their associated values, and only then execute the command. Thus, if a variable itself contains a valid command, Command Prompt will expand it, and then execute the command it contains.
This example also reveals an interesting implication to placing quotation marks around the value of the variable when it is defined. If we were to do that, and then attempt to evaluate the variable as a command,
% set pyf=.\*.py
% set target=C:\users\douglas\documents\python
% set mcmd="move %pyf% %target%"
% cd dir1
% %mcmd%
Can't recognize "move .\*.py C:\users\douglas\documents\python"
as an internal or external command, or batch script.
You see that we get an error. Because the quotation marks are directly included with the value of the variable, after all of the variable expansions, the quotes remain. So the shell interprets our command, and its arguments, as though it were the name of a single command–which it obviously cannot find.
Again, note that this particular behavior is a bit idiosyncratic to Command Prompt. On many other shells, the quotation marks are not saved to the variable when an assignment is made, and quotes may even be necessary when the value contains spaces.
Conclusion
In this chapter, we saw the basic usage of variables in Command Prompt, how to set them, access their values, do basic arithmetic, and use them as part of commands. In the next chapter, we’ll look a little more deeply into another aspect of variables: their use in configuring your shell environment and the behavior of programs, in the form of environment variables.
Postscript – a note on Linux shells
As one of the goals of this tutorial is to introduce shell concepts in a Windows environment, with the ultimate hope that these skills will translate generally to other shells, I want to make a final note on variables as they pertain to bash, and other similar shells.
The thirty second introduction to variables in bash is that you can create them
using the same basic <name>=<value>
syntax as we just saw, except without
needing to use a special command, like set
. And then, instead of using
percent signs, you use a dollar sign to get their value. For example,
# bash
% x=123
% echo $x
123
If you want spaces in the value, you need to use quotation marks (otherwise you’ll get an error), and you also need quotes when you access the value (if you want to treat the whole thing as one argument),
# bash
% var="with a space.txt"
% mv "$var" new_name.txt
Hopefully this helps to demonstrate how, though there are differences, a lot of the basic concepts of command line shell usage remain constant from shell to shell.
Getting finally to the major point I wanted to make here, this chapter was missing one very important (and useful) piece of functionality related to variables: taking the output of a command and storing it in a variable.
I left this out because it isn’t something that is easy to do in Command Prompt, and would require either temporary files (which we’ll talk about in a future chapter), or some more advanced concepts that we won’t discuss at all (such as for loops). In bash, however, this is something that is easily accomplished, like so,
# bash
% var=$(echo "hello there!")
% echo "$var"
% hello there!
by placing the command you want to capture the output of inside of parentheses, with a leading dollar sign, and then assigning that whole thing to a variable.
variable_name=$(command)
As we’re strictly using interactive features of the shell at the moment, the simplest workaround to lacking this feature in Command Prompt is copy-paste. For cases when the output is too large to conveniently copy and paste, it would be better to use temporary files to store the results, which will be discussed in a later chapter.
-
Two notable exceptions to this limitation are modern incarnations of the Korn shell (ksh93), and Microsoft PowerShell, both of which support floating point arithmetic directly. ↩︎