KornShell (ksh) Variables Tutorial

Variables & Macro Expansion

1 Variable Assignment

In ksh, a variable stores a value that can be reused later in commands or scripts. Assigning a value to a variable is straightforward: write the variable name, immediately followed by an equals sign and the value — with no spaces around the = sign.

Syntax

name=value

Some practical examples:

greeting=Hello
count=42
filename=report.txt
dir=/home/user/documents
Important: There must be no spaces on either side of the = sign. Writing name = value is a syntax error because ksh will interpret name as a command name.

Variable names may contain letters, digits, and underscores, and must begin with a letter or underscore. By convention, environment variables (those used by the system) are in UPPER_CASE, and variables used in scripts use lower_case, though ksh does not enforce this.

2 Macro Expansion

Macro expansion (also called parameter expansion or variable substitution) is the process by which ksh replaces a variable reference or expression with its current value before executing a command. The echo command is ideal for exploring expansion because it simply prints whatever arguments it receives. You may be familiar with echo from MS-DOS and Windows, where variables are bracketed with a % character. But Unix shell variables are a more mature system.

2.1 The $ Prefix for Variable Names

Prefix a variable name with $ to expand it. The shell sees a $ and knows that what follows is something it needs to substitute. It’s not just used for variables, but this is a common use case.

Basically the shell goes through a line it’s about to run and “fixes up” anything prefixed with a $, and certain other characters, before it runs it.

Command
city=Swansea
echo $city
Output
Swansea

You can embed variable expansions anywhere in a string or command line:

Command
user=Alice
echo “Hello, $user!”
Output

Hello, Alice!

If your variable expansion runs on into more alphanumeric characters you will need to wrap it in a { and } to avoid ambiguity. Otherwise the { and } are optional.

Command
ext=jpg
echo “photo.${ext}”

dir=/var/tmp
echo $dir123
echo ${dir}123
Output

photo.jpg



Problem! No output /var/tmp123
Tip: Using ${varname} to avoid ambiguity, but omitting it can sometimes improve readability

2.2 Glob Expansion

Glob expansion (also called pathname expansion or filename generation) lets you use wildcard characters in a command to match multiple file or directory names. ksh performs the expansion before passing the resulting list to the command.

Common wildcard characters

* matches any sequence of characters (including none) ? matches exactly one character [abc] matches any one of the listed characters [a-z] matches any character in the given range

Examples using echo to reveal what the shell expands:

Command
echo /etc/*.conf
Output
/etc/host.conf /etc/nsswitch.conf /etc/resolv.conf …
Command
echo file?.txt
Output
file1.txt file2.txt file9.txt
Command
echo report_[0-9][0-9].csv
Output
report_01.csv report_12.csv report_99.csv
Note: If no files match a glob pattern, ksh leaves the pattern unchanged and passes it literally to the command. This is a common source of confusion when a path does not yet exist.

2.3 Command Substitution: $() Syntax

Command substitution lets you capture the output of a command and use it as a value — either storing it in a variable or embedding it directly in another command.

result=$(command)

The shell runs command in a subshell, collects its standard output (with trailing newlines stripped), and substitutes the result in place of the $(…) expression. Note that the date command prints the current time and date, and the format of it’s output can be modified using a template prefixed with +. We’ll cover this later. The wc -l command simply counts the number of lines in the input.

Command
today=$(date +%Y-%m-%d)
echo $today
Output
2024-03-15
Command
echo “You have $(ls | wc -l) files here.”
Output
You have 23 files here.

Backtick alternative

An older syntax uses backtick characters ( ` ) instead of $(…). This is the character on the keyboard found on most keyboards to the left of the digit 1.It’s equivalent in basic use:

result=`command`

# These two lines produce identical results:
today=$(date +%Y-%m-%d)
today=`date +%Y-%m-%d`

The $() form is strongly preferred for several reasons:

  • It can be nested cleanly: $(outer $(inner))
  • Backticks require backslash-escaping inside nested calls, which quickly becomes unreadable.
  • $() syntax is visually clear and consistent with other shell constructs.
  • It’s easy to miss a back-tick or confuse it with an apostrophe.
Tip: Use $() in all new scripts. Backticks are found in older scripts and are worth recognising, but should not be written in new code, but are less typing if you’re running a one-off command.

3 Quoting to Prevent Expansion

Sometimes you want ksh to treat special characters — $ * ? and others — literally rather than expanding them. Quoting provides three ways to do this, each with different scope and purpose.

3.1 Backslash ( \ )

A backslash immediately before a character escapes that single character — the shell treats the following character literally instead of interpreting it.

Command
price=5
echo The cost is \$price
Output
The cost is $price
Command
echo show \* without glob
Output
show * without glob

Backslash escape is precise: it affects only the one character that immediately follows it.

3.2 Single Quotes ( ‘ )

Enclosing text in single quotes prevents all expansion within those quotes. Every character is taken literally — the shell performs no substitution, no glob expansion, and no command substitution.

Command
name=World
echo ‘Hello $name’
Output
Hello $name
Command
echo ‘*.txt files are $important’
Output
*.txt files are $important
Note: You cannot include a single-quote character inside a single-quoted string. To use a literal single quote, end the string, escape the quote with a backslash, and reopen the string: echo ‘it’\”s here’

3.3 Double Quotes ( ” )

Double quotes suppress glob expansion and word splitting, but still allow variable expansion ($var and ${var}) and command substitution ($(…)). They are the most commonly used form of quoting in scripts.

Command
name=Alice
echo “Hello, $name”
Output
Hello, Alice
Command
echo “Today is $(date +%A)”
Output
Today is Wednesday
Command
echo “No glob: *.txt”
Output
No glob: *.txt

Quick comparison

Quoting$var expansion$() substitutionGlob expansion
\backslashYes (next char only)Yes (next char only)Yes (next char only)
‘single quotes’NoNoNo
“double quotes”YesYesNo
(no quoting)YesYesYes

4 Using a Variable in a Command

A practical and very common use of variable expansion is building up path names or directory fragments that are then passed to commands such as ls.

Partial directory name in ls

Suppose you are frequently working inside a versioned project directory and do not want to retype the path each time. Store part of the path in a variable and let the shell expand it for you:

# Store a partial path
project=/home/alice/projects/webapp

# Use it with ls to list a subdirectory
ls ${project}/src

# Combine with a glob to find only Python files
ls ${project}/src/*.py

# Use in a longer path with another variable
subdir=tests
ls ${project}/${subdir}

Notice that braces are used around the variable name (i.e. ${project}) to avoid unexpected problems if there was something funny in $project.

You can also store just a partial directory segment — a prefix — and rely on glob expansion to complete it:

# List all log directories for a given year
year=2024
ls /var/log/app/${year}-*

# List any directory whose name starts with ‘web’
prefix=web
ls /srv/${prefix}*/html
Command
prefix=web
ls /srv/${prefix}*/html
Output
/srv/webapp/html /srv/webapi/html /srv/webstatic/html
Tip: Always quote the expanded variable in double quotes if the path might contain spaces: ls “${project}/My Documents”

5 Exercises

Work through the following exercises at a ksh prompt. Type the commands exactly as shown, observe the output, then experiment with variations to deepen your understanding.

Section A — Variable Assignment and $ Expansion

Exercise 1: Assign your first name to a variable called firstname and your surname to lastname. Use echo to print both on a single line in the form Firstname Lastname. Hint: Two separate echo arguments, or embed both variables in one double-quoted string.
Exercise 2: Create a variable ext with the value txt. Then use echo with brace syntax (${}) to print the string myfile.txt without writing .txt literally in the echo command. Hint: echo “myfile.${ext}”
Exercise 3: Assign any number to a variable n. Use echo to print the line: The value of n is: 42 (substituting your number). Then change n to a different number and run the same echo command again without retyping it — use the Up arrow to recall it. Hint: Re-run with !! or the Up arrow after changing n.

Section B — Glob Expansion

Exercise 4: Run echo /etc/p* and observe which files and directories are matched. Then try echo /etc/p*.conf — how does the output differ? Hint: The * wildcard matches any sequence of characters.
Exercise 5: In your home directory, create three files named note1.txt, note2.txt, and notex.txt using touch. Then use echo note?.txt and explain what the ? wildcard matched compared to echo note*.txt. Hint: touch note1.txt note2.txt notex.txt — then compare the two echo outputs.
Exercise 6: Use echo with a character-class glob to list only files in /etc whose names begin with a vowel (a, e, i, o, or u). Hint: echo /etc/[aeiou]*

Section C — Command Substitution

Exercise 7: Capture the current working directory into a variable called here using $() and the pwd command. Then echo the sentence: You are in: /your/path Hint: here=$(pwd)
Exercise 8: Store the number of lines in /etc/passwd into a variable usercount using $() and wc -l. Print a sentence such as: There are 42 users in /etc/passwd. Hint: usercount=$(wc -l < /etc/passwd)
Exercise 9: Rewrite your answer to exercise 7 using backtick syntax instead of $(). Confirm the output is identical, then consider: which form do you find easier to read? Hint: here=`pwd`

Section D — Quoting

Exercise 10: Assign the string don’t stop to a variable msg. Then echo $msg and verify the apostrophe is preserved. (Hint: use double quotes for the assignment: msg=”don’t stop”) Hint: Double quotes allow the apostrophe inside the string.
Exercise 11: Run these three commands and explain why each produces different output: name=World echo Hello $name echo ‘Hello $name’ echo “Hello $name” Hint: Unquoted and double-quoted expand $name; single-quoted does not.
Exercise 12: Use a backslash to print the literal string Cost: $10.00 without ksh expanding $10 as a variable. Try both the backslash approach and the single-quote approach and confirm they give the same result. Hint: echo Cost: \$10.00 vs echo ‘Cost: $10.00’

Section E — Variables in Commands

Exercise 13: Set a variable logdir to /var/log. Use it in an ls command to list all files in that directory ending in .log. Use brace syntax for the variable. Hint: ls ${logdir}/*.log
Exercise 14: Store a partial directory name — such as sys — in a variable called fragment. Then use ls with a glob combining ${fragment} and * to list any matching entries under /var/log. Hint: fragment=sys; ls /var/log/${fragment}*
Exercise 15: Create variables for the first part of a filename and its extension. Use echo (not ls) to demonstrate that combining them with ${} produces the expected filename string — for example report_2024.pdf. Hint: base=report_2024; ext=pdf; echo “${base}.${ext}”

Leave a Reply

Your email address will not be published. Required fields are marked *