Skip to content
Français
Account: not signed in, sync available My learning
Select theme
Français

By updated

Improve this page

When you type ls *.txt, the shell replaces *.txt with the list of matching files before running ls. That is an expansion: the shell transforms what you write into something more precise. Understanding these mechanisms lets you write short, powerful commands instead of repeating the same operations by hand.

What you will learn

  • Use the wildcards (*, ?, [...]) to target files
  • Generate sequences with the braces {a,b} and {1..5}
  • Use the tilde ~ as a shortcut to the home directory
  • Insert the result of a command with $()
  • Compute a simple calculation with $(())
  • Choose between single and double quotes

What is globbing?

Globbing (pattern expansion) is the most used mechanism. The shell replaces the patterns with the list of files that match them.

The star *: zero or more characters

The star matches any run of characters, including none. It is the wildcard you will type most often:

Terminal window
ls *.txt

Shows every file whose name ends in .txt in the current directory.

Terminal window
ls report*

Shows every file whose name starts with report.

The question mark ?: exactly one character

The question mark stands for one character, no more and no less, which makes it stricter than the star:

Terminal window
ls file?.txt

Matches file1.txt, fileA.txt, but not file12.txt (two characters after file).

Brackets [...]: one character from a list

Brackets also match a single character, but only one of those listed:

Terminal window
ls file[123].txt

Matches file1.txt, file2.txt, file3.txt.

You can also use a range:

Terminal window
ls file[a-z].txt

Matches filea.txt, fileb.txt, and so on.

Combine the wildcards

Wildcards can appear anywhere in a path, and they mix with the braces seen further down:

Terminal window
ls /var/log/*.log
ls /etc/*.d/
ls *.{txt,md}

Test without risk

To see what the shell will expand, use echo instead of the real command:

Terminal window
echo *.txt

The shell prints the list of matching files without running anything.

How do braces generate sequences?

Braces {} generate a list of values. Unlike globbing, braces do not depend on existing files.

Explicit list

The simplest form lists the values between braces, separated by commas and without spaces. The shell then produces as many arguments as there are items, and this expansion happens before the command runs.

Terminal window
echo {red,green,blue}
Output
red green blue

It is handy to create several folders at once with mkdir -p, in a single command:

Terminal window
mkdir -p project/{src,docs,tests}

This creates three subfolders in project/.

Numeric sequence

The two dots between two numbers produce the full range, bounds included. It is the form used to create numbered files or directories in a single command, without writing a loop.

Terminal window
echo {1..5}
Output
1 2 3 4 5
Terminal window
touch file{01..10}.txt

This creates file01.txt to file10.txt.

Alphabetical sequence

The same mechanism works on letters, in alphabetical order. The benefit is the same: produce a series of names that do not exist yet, which globbing cannot do since it starts from the files that are present.

Terminal window
echo {a..f}
Output
a b c d e f

How does the tilde expand?

The ~ character is replaced by the path of your home directory, before the command runs:

Terminal window
echo ~
Output
/home/bob

~/Documents is the same as /home/bob/Documents.

The tilde also accepts an attached account name: ~alice designates Alice's home directory, that is /home/alice, provided the account exists on the machine. Otherwise, the shell leaves the string as is, which produces a literal ~alice path and a file-not-found error.

How does command substitution $() work?

The $(command) syntax runs the command between the parentheses and replaces the whole thing with its output:

Terminal window
echo "Today is $(date +%Y-%m-%d)"
Output
Today is 2026-04-06

Another example: store the result in a variable, to reuse it in the rest of a script:

Terminal window
FILE_COUNT=$(ls | wc -l)
echo "There are $FILE_COUNT files here"

Command substitution is very useful in scripts to capture information dynamically.

How does arithmetic $(()) work?

Bash can compute without calling an external program, on one condition: it only handles integers. A division therefore returns an integer quotient, $((7 / 2)) being 3 and not 3.5, and there are no decimal numbers. For a decimal calculation, you need a tool such as bc or awk.

To compute with integers, put the expression between double parentheses preceded by a $:

Terminal window
echo $((3 + 7))
Output
10

Available operators: +, -, *, / (integer division), % (modulo).

Terminal window
TOTAL=$((512 * 1024))
echo "$TOTAL bytes"

Single or double quotes: which one should you use?

The choice of quotes decides whether the shell interprets variables and expansions or not.

Double quotes "...": the shell interprets

Inside double quotes, the shell still replaces variables and substitutions:

Terminal window
NAME="Alice"
echo "Hello $NAME"
Output
Hello Alice

The expansions $NAME, $(command) and $((calculation)) are interpreted.

Single quotes '...': the shell interprets nothing

Single quotes disable every expansion: variables, command substitutions and calculations are passed as they are. They are therefore the ones to use for literal text, a regular expression, or a password containing a $.

Terminal window
echo 'Hello $NAME'
Output
Hello $NAME

The text is taken literally.

When to use which

The rule fits in one question: do you want the shell to replace something in the text? If so, double quotes; if not, single quotes.

SituationQuotes
Text with variables to replace"..."
Literal text with no replacement'...'
Command with spaces in a path"..."

A habit to adopt right now: always wrap your variables in double quotes, in the form "$MY_VAR". Without them, a space in the value is read as an argument separator, and a command that was supposed to receive one file name receives two. The defect only shows with values that contain a space, so never during tests.

Troubleshooting

These 5 symptoms share a common root: expansion happens in the shell, before the command runs. The error message therefore comes from the command, which received something other than what you thought you gave it, and never mentions the expansion itself. When in doubt, replace the command with echo to see what it would have received.

SymptomLikely causeFix
ls *.txt prints cannot access '*.txt': No such file or directoryNo .txt file in the directory: Bash passes the pattern unchangedCheck with ls, then adjust the pattern
mkdir {a, b} creates two folders named {a, and b}Space after the comma: the braces are no longer expandedWrite {a,b} with no spaces and without '...'
$NAME prints the literal textVariable wrapped in single quotes '...'Use double quotes "..."
$(3 + 7) prints 3: command not foundSingle parentheses: $() runs a command instead of computingWrite $((3 + 7)) with double parentheses
$((1 / 2)) returns 0Bash only computes with integers: division truncatesMultiply before dividing, or use bc or awk for decimals

Key points

  • Globbing (*, ?, [...]) matches the names of existing files.
  • Braces {a,b} and {1..5} generate lists, independently of files.
  • ~ is the shortcut to your home directory.
  • $(command) inserts the result of one command into another.
  • $(()) handles integer calculations.
  • Double quotes "..." interpret variables, single quotes '...' do not.

Knowledge check

Check that the essentials of this guide stuck. The questions cover only what has just been explained here.

Knowledge check

Check what you have learned with this interactive quiz

6 questions
6 min
70% to pass

How it works

  • The timer starts when you click Start
  • Multiple choice, true/false and short answer questions
  • You can move between questions
  • Detailed results are shown at the end

Starts the quiz and the timer

Is this project useful to you?

The guides, courses, quizzes and labs stay free. If you use them regularly, you can contribute to their upkeep and development.

Become a supporting member (new tab) One-time support (new tab) Learn more

Follow the project on LinkedIn