Learn › Linux Foundations › Bash Shell Environment
ls - a hands-on Linux lab on a real virtual machine.
Act on many files with one short pattern using shell globs. Match any run of characters with , exactly one with ?, and one from a chosen set with []. See why a pattern that matches nothing is passed through literally, and how quotes switch expansion off. The shell expands the glob into real filenames before your command runs.
You are standing in a folder with five files in it: file1.txt, file2.txt, file3.log, notes.md, and image.png. You want to see just the text files, the two ending in .txt. You could type both names out. But what if the folder held five hundred files?
There is a better way. You hand the shell a short pattern with a * in it, and the shell expands that pattern into the full list of matching filenames before the command even runs. One tiny pattern, and ls acts on exactly the files you meant. These patterns are called globs, and every Linux engineer leans on them daily.
The black boxes in this lesson are a practice terminal: a safe sandbox that only checks the one command each step teaches, so you cannot break anything. This folder is pinned to the same five files every time, so the outputs you see here are exactly what a real shell prints against this folder. ls just lists names, so nothing here can change or delete a file.
A glob is a pattern of ordinary text plus one or more wildcards, special characters that stand in for other characters. The most common wildcard is *, the star, and it means any run of characters, including none. So the pattern *.txt reads as anything, then .txt.
Here is the part that surprises people. The glob is not handled by ls. It is handled by the shell, before ls ever runs. When you type ls *.txt, the shell looks at the filenames in the current folder, swaps *.txt for the real names that match, and only THEN starts ls. By the time ls sees anything, the star is already gone, replaced by a list of actual files.
Think of it like a mail merge. You write one letter that says Dear [name], and the machine stamps out one copy per real name in the list. You write one pattern; the shell stamps out the matching filenames.
Enough theory. Ask for the two text files with a single star:
ls *.txt
prompt: student@linuxcamp:~$ answer: ls *.txt output: file1.txt file2.txt hint: Type ls, a space, then a star touching .txt with no space between them: ls *.txt
Two names came back: file1.txt and file2.txt. The star matched file1 and file2, the run of characters sitting in front of .txt, and it ignored file3.log, notes.md, and image.png because none of those end in .txt. Remember, ls never saw the star. The shell had already turned *.txt into file1.txt file2.txt and handed ls those two real names. That is globbing: the shell expands the pattern, the command acts on the result.
The star matches any run of characters, even an empty one. Its quieter cousin, the question mark ?, is stricter: it matches EXACTLY ONE character, no more and no less. Where * says any amount, ? says precisely one.
This strictness is easy to trip over, so let us watch it fail first, on purpose. Before you run the next line, decide what you expect. The pattern file? means file followed by exactly one character. Do any of the five files fit that? Run it and see:
ls file?
prompt: student@linuxcamp:~$ answer: ls file? output: ls: cannot access 'file?': No such file or directory hint: Type ls, a space, the word file, then a single question mark: ls file?
Nothing matched, so ls complained. Look at why. file? demands file plus exactly ONE more character and then the name ends. But file1.txt has five more characters after file, the 1, the dot, and txt. So file? fits none of them. When a glob matches nothing, the shell hands the pattern to ls unchanged, and ls tries to open a file literally named file?, which does not exist. That is the error you are reading. You will meet it again in a moment, because it is the classic glob surprise.
The question mark was not wrong, it was just aimed at the wrong spot. file1.txt has exactly one character, the 1, sitting between file and .txt. So put the ? right there, between file and .txt, and it should match the digit in both text files.
The pattern file?.txt reads as file, then exactly one character, then .txt. Aim it and run:
ls file?.txt
prompt: student@linuxcamp:~$ answer: ls file?.txt output: file1.txt file2.txt hint: ls, a space, then file, one question mark, then .txt with no spaces: ls file?.txt
Both text files came back. The ? matched the single character between file and .txt, the 1 in file1.txt and the 2 in file2.txt. It did NOT match file3.log, because that name ends in .log, not .txt. This is the heart of ?: it is a placeholder for one character, no matter which character. Where *.txt matched any run before .txt, file?.txt insists on exactly one character in that slot.
Sometimes you do not want any character, you want one from a short list you choose. Square brackets do that. [fn] means exactly one character, and it must be either f or n. Whatever you list inside the brackets is the menu; the shell picks one slot and fills it from that menu.
So [fn]* reads as a name starting with f or n, then anything after. In this folder, that is every file beginning with f (the three file names) plus every file beginning with n (that is notes.md). The image.png name starts with i, which is not on the menu, so it is left out. Run it:
ls [fn]*
prompt: student@linuxcamp:~$ answer: ls [fn]* output: file1.txt file2.txt file3.log notes.md hint: ls, a space, then f and n inside square brackets, then a star: ls [fn]*
Four names: file1.txt, file2.txt, file3.log, and notes.md. The bracket [fn] filled the first character slot with either f or n, and the * swept up the rest of each name. image.png was the only file left out, because i was not inside the brackets. Two shortcuts worth knowing: a range like [a-z] means any one lowercase letter, and a leading ! or ^ flips the set, so [!f]* would mean names that do NOT start with f.
The real power shows up when you mix wildcards. Say you want both the .txt and the .log files in one shot, but not the .md or .png. Both .txt and .log begin their extension with a different letter, t and l. So pick those two letters from a bracket set.
The pattern *.[tl]* reads as anything, then a dot, then a t or an l, then anything. That catches every file whose extension starts with t or l, which is the three .txt and .log files. Run it:
ls *.[tl]*
prompt: student@linuxcamp:~$ answer: ls *.[tl]* output: file1.txt file2.txt file3.log hint: ls, a space, star, dot, then t and l inside brackets, then a star: ls *.[tl]*
Three files: the two .txt and the one .log. The first * matched each name up to the dot, the [tl] picked the first letter of the extension as t or l, and the trailing * matched the rest of the extension. notes.md and image.png were skipped, because m and p were not in the bracket. You just selected on two file types at once with a single pattern, which is the kind of move that saves real time on a crowded folder.
You saw the error once with file?. It is worth meeting again on purpose, because it is the glob behaviour that confuses beginners the most. Ask for a file type that simply is not here. No file in this folder ends in .xyz.
Before you run it, decide what you expect. Will the shell print an empty line, or something else? Try it:
ls *.xyz
prompt: student@linuxcamp:~$ answer: ls *.xyz output: ls: cannot access '*.xyz': No such file or directory hint: ls, a space, then a star touching .xyz: ls *.xyz
This is the surprise. When a glob matches NO files, bash does not blank it out. By default it passes the pattern through to the command UNCHANGED. So ls received the literal text *.xyz, tried to find a file with that exact name, and failed with No such file or directory. The star is right there in the error message, a dead giveaway that your pattern matched nothing. When you see a lone * in an error like this, read it as the pattern found no files, not as a broken command.
One more essential. What if you want the shell to leave a * alone, to treat it as a plain star and not expand it at all? You wrap it in quotes. Quotes tell the shell this is literal text, hands off, so no globbing happens.
Watch the difference with echo, a command that just prints its argument back. Quote the pattern so the shell never touches it:
echo "*.txt"
prompt: student@linuxcamp:~$ answer: echo "*.txt" output: *.txt hint: Type echo, a space, then *.txt wrapped in double quotes: echo "*.txt"
It printed the literal *.txt, star and all. The double quotes switched globbing off for that word, so the shell handed echo the raw pattern instead of a file list. Try the same line without the quotes, echo *.txt, and the shell would expand it first and echo would print file1.txt file2.txt instead. Quoting is how you send a * or ? to a command as plain text, which matters the day you need to search FOR a star rather than match with one.
Scaffolding off. No pattern is printed this time. You have every piece you need.
You want to list image.png and only image.png. Here is the twist: match it by the SHAPE of its name, not by typing the name out. The file is called image, then a dot, then an extension of exactly three characters. Build a pattern that says the word image, a dot, then exactly three of any character. Recall that the wildcard for exactly one character is the question mark.
prompt: student@linuxcamp:~$ answer: ls image.??? output: image.png hint: Exactly one character is a single question mark. Three characters means three question marks in a row, after image and a dot.
That is the move. image.??? reads as image, a dot, then exactly three characters, and png is exactly three characters, so it matched image.png and nothing else. Each ? filled one slot in the extension. You built a pattern from the SHAPE of a filename rather than its exact spelling, using three question marks from memory, which is the same recall a real machine will ask of you.
You earned this cheat sheet. Every wildcard here is one you just used against the five-file folder:
And the patterns you ran, each solving a real selection:
A glob is not a regular expression, though they look alike. Globs are simpler: the shell uses them to match whole FILENAMES in a folder, and * in a glob just means any run of characters. In a regular expression, which you meet in the text-processing lessons, * means something different and the rules are richer. For now, hold one line: globs match files, and the SHELL does the matching before your command runs.
The practice terminal has shown you the shape of globbing. You can match a run of characters with *, exactly one with ?, and one from a chosen set with []. You saw what happens when a pattern matches nothing, and how quotes switch expansion off. Every one of those you typed yourself.
The Bash Environment module ends with one real Linux machine, the Bash Environment capstone mission, and that is where you use globs for real. A VM boots just for you, with its own live folders full of files. It hands you objectives that use exactly what you practiced across this module: variables, exports, the command lookups, aliases, quoting, and the wildcards you just learned. One difference from here: the mission shows no commands. You read the objective, you recall the pattern, you type it. That recall is what makes it stick.
Finish the other Bash Environment lessons, then go match real files for yourself.
Practice Glob Patterns in a real Linux terminal at The Linux Camp. Progress is verified automatically as you type commands on the machine.