Your country

Tools that support it use your country for local currency, number formats, units and paper size. Your choice is saved only in this browser.

Type a name or a two-letter code. Use the up and down arrow keys to move through the countries, Enter to choose one and Escape to close.

Bash & the POSIX Shell  Module 1 – Start here: the shell, the terminal and your first script

Commands, options, arguments and help

Split a command line into its name, options, option-arguments and operands, end options with --, and find help with type, help, man and --help.

  • Beginner
  • 5 minutes
  • Examples run with Bash 5.3.20, dash 0.5.13.5, shellcheck 0.11.0 and Python 3.14.8
  • By MySmartCoPilot
Free lesson, Pro answers: 5 minutes
Free: the whole lesson. With a pass: the model answers to its 2 interview questions.

What you will learn

  • Split a command line into its command name, options, option-arguments and operands
  • Use -- to end options and handle file names that start with a dash
  • Find help with type, help, man and --help, and tell keywords, builtins, functions, aliases and files apart

Before you start

What you’ll learn · Before you start

What you will learn

  • Split a command line into its command name, options, option-arguments and operands
  • Use -- to end options and handle file names that start with a dash
  • Find help with type, help, man and --help, and tell keywords, builtins, functions, aliases and files apart

Before you start

On this page

In a folder that holds a file called -n, the command cat * prints one numbered line instead of the contents of both files, and nothing warns you: cat read the file’s name as its “number the lines” option. Knowing how a command line splits into a name, options and operands is what lets you see that coming.

Below you will take command lines apart into their pieces, watch a glob turn a file name into an option and fix it with --, follow the order in which Bash decides whether a name is an alias, a keyword, a function, a builtin or a program, and find the right help for each kind of command.

A command line is a name, options, option-arguments and operands

Take head -n 2 drinks.txt. The first word, head, is the command name. -n is an option: A word that starts with a dash and changes how a command behaves, such as -n for head. One-letter options without values can usually be grouped behind one dash, as in cat -ne., 2 is its option-argument, the value the option needs, and drinks.txt is an operand: A word after a command's options that the command works on, usually a file name. After --, every word is an operand, even one that starts with a dash., the thing the command works on. POSIX.1-2024’s utility syntax guidelines describe this shape for standard utilities, and most other programs follow it.

Part In head -n 2 drinks.txt In cat -ne drinks.txt
Command name head cat
Options -n -n and -e, grouped
Option-argument 2 (belongs to -n) none
Operands drinks.txt drinks.txt

The guidelines also allow one-letter options without arguments to be grouped behind a single dash, so cat -ne means cat -n -e. Here are both forms on a three-line file, with -n numbering the lines and -e marking each line’s end with $:

Options written apart and grouped Python · anatomy_session.py
from session import run

# One small file, then the same options written apart and grouped behind one dash.
run("""
printf 'tea\\ncoffee\\nwater\\n' > drinks.txt
head -n 2 drinks.txt
cat -n -e drinks.txt
cat -ne drinks.txt
""")

Output

$ printf 'tea\ncoffee\nwater\n' > drinks.txt
$ head -n 2 drinks.txt
tea
coffee
$ cat -n -e drinks.txt
     1	tea$
     2	coffee$
     3	water$
$ cat -ne drinks.txt
     1	tea$
     2	coffee$
     3	water$

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 anatomy_session.py

The two cat commands print exactly the same lines, because grouping changes only how the options are written.

Many programs also accept long options, whole words after two dashes such as --help or --color=never. They are a convention of GNU and other projects rather than one of the POSIX guidelines, so a long option that works on Linux may be missing from the macOS version of the same command, as the last section of this lesson shows with ls --help. When a script must run on both, prefer the short options that POSIX describes for the utility.

Reading an option-argument as an operand

Wrong: “head -n 2 drinks.txt works on two files, 2 and drinks.txt”. Right: 2 belongs to -n, so only drinks.txt is an operand. A command that takes an option-argument reads the next word for it, whatever it looks like.

Two dashes end the options, so a file named like an option stays a file

The shell expands * into the names of the files in the folder before the command starts, and the command cannot tell a word that came from a file name from one you typed. POSIX guideline 10 gives the cure: the first -- that is not an option-argument marks the end of the options, and every word after it is an operand, even one that begins with a dash. Watch a file called -n change what cat * does:

A file named -n, a glob and two fixes Python · dash_file_session.py
from session import run

# A file whose name starts with a dash, and a glob that hands that name to cat.
run("""
printf 'hello\\n' > -n
printf 'world\\n' > notes.txt
ls
cat *
cat -- *
cat ./*
rm -- -n
ls
""")

Output

$ printf 'hello\n' > -n
$ printf 'world\n' > notes.txt
$ ls
-n
notes.txt
$ cat *
     1	world
$ cat -- *
hello
world
$ cat ./*
hello
world
$ rm -- -n
$ ls
notes.txt

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 dash_file_session.py

cat * became cat -n notes.txt, so cat numbered the one file it was given and never printed “hello”. Both fixes work: cat -- * ends the options before the file names, and cat ./* makes every name start with ./, which is not a dash. Even removing the file needs the same care, which is why the session uses rm -- -n. ShellCheck warns about a bare * in arguments for exactly this reason (SC2035).

Key idea

A glob hands file names to a command as ordinary words, so write -- * or ./* whenever a name could start with a dash.

Checkpoint

Check: Name, options and operands · Ending options with --

  1. Question 1 of 2 In tail -n 3 log.txt, which word is the operand?

    Choose one answer.

    Show the answer: Question 1 of 2

    Answer: log.txt

    The command name comes first, then options with their option-arguments, then operands. -n takes the value 3, so only log.txt is left to be an operand.

  2. Question 2 of 2 A folder holds the files -n and notes.txt. Why did cat * print one numbered line instead of both files?

    Choose one answer.

    Show the answer: Question 2 of 2

    Answer: The shell expanded * to -n notes.txt, and cat read -n as its option

    cat * became cat -n notes.txt. Write cat -- * or cat ./* so that no file name can start with a dash where an option could go.

The type builtin shows what a name means, and command tells whether it exists

The same word can mean several things. if is a keyword of the shell’s language, echo is a builtin: A command that is part of the shell itself rather than a separate program, such as cd, echo or type in Bash. help NAME documents it. compiled into Bash and also a program in /bin, ls is only a program, and you can make a name into a function or an alias yourself. Bash’s reference manual gives the order in which it decides: aliases and keywords are recognised while the line is read, then come functions, then builtins, then a search of the folders in PATH, remembered in a hash table. Follow one name down that order:

Interactive · stage by stage How Bash decides what a command name means Follow one name down the column. The first stage that recognises it decides what runs; a name nothing recognises ends with exit status 127.
How Bash decides what a command name means, step 6 of 6. Showing Alias or keyword?, A function?, A builtin?, A remembered path?, Search PATH, Not found. In focus: Not found.Alias or keyword?while reading: ll, ifA function?greetA builtin?echo, printf, cdA remembered path?hash table of past findsSearch PATHls is /bin/lsNot foundexit status 127

The drawing shows the whole scene; its 6 steps are listed below.

Every step as text
  1. While the line is read. Before anything runs, Bash checks the first word against its keywords, such as if, and its aliases, such as ll. An alias is replaced by its text, so ll becomes ls -l.
  2. Functions come first. A name that is not an alias or keyword is looked up as a function. The greet function defined in the terminal wins over any program of the same name.
  3. Then builtins. Next come the builtins compiled into Bash, such as echo, printf and cd. That is why type -a lists echo as a shell builtin before the program /bin/echo.
  4. Then the hash table. For a program, Bash first looks in its hash table of full paths it found earlier, so it need not search PATH every time. hash -r empties it.
  5. Then every folder in PATH. Otherwise Bash searches the folders of PATH in order and runs the first executable file with that name, such as /bin/ls.
  6. Nothing matched. When no stage recognises the name, Bash prints "command not found" and the command's exit status is 127, which scripts can test.

type -a NAME prints every meaning a name has, in that order, and command -v NAME prints how the name would run, or nothing with status 1 when it does not exist. Here they are after a function and an alias have been defined:

What kind of command is each name? Python · lookup_session.py
from session import run

# What kind of command is each name? A function and an alias are defined first, as you might in a terminal.
run("""
greet() { echo "hi, $1"; }
alias ll='ls -l'
type -a echo printf ls
type if greet ll
command -v ls
!command -v nosuchcmd
command -v nosuchcmd || echo missing
""")

Output

$ greet() { echo "hi, $1"; }
$ alias ll='ls -l'
$ type -a echo printf ls
echo is a shell builtin
echo is /bin/echo
printf is a shell builtin
printf is /usr/bin/printf
ls is /bin/ls
$ type if greet ll
if is a shell keyword
greet is a function
greet ()
{
    echo "hi, $1"
}
ll is aliased to `ls -l'
$ command -v ls
/bin/ls
$ command -v nosuchcmd
[exit status 1]
$ command -v nosuchcmd || echo missing
missing

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 lookup_session.py

type -a found echo twice, as a builtin and as /bin/echo; typing echo runs the builtin because builtins come first. For nosuchcmd, command -v printed nothing and ended with status 1, which is why command -v nosuchcmd || echo missing printed “missing”. In a script, command -v is the portable way to ask whether a command exists, because POSIX defines it for every shell.

PATH itself is a list of folders separated by colons, searched from left to right, and the first folder that holds an executable file with the name wins. Bash remembers each program it finds in its hash table, so after you install a new copy of a program earlier in PATH, an open terminal may keep running the old one until you type hash -r or open a new terminal. type tells you when that happens: it answers “ls is hashed (/bin/ls)” for a remembered name.

Using which to test for a command in a script

Wrong: if which jq in a script. Right: if command -v jq >/dev/null. which is a separate program that POSIX does not define, and its output and exit status differ between systems, while command -v behaves the same in every POSIX shell.

help, man and the help option each document a different kind of command

Where you find documentation depends on what kind of command you have. Builtins are documented inside Bash, by the help builtin. Programs installed on the system usually have a manual page, which man shows and man -w locates. Many programs, including Bash’s builtins from Bash 4.4 on, also answer --help with a short usage line, but not all of them: macOS’s own ls rejects the option.

Three places to look for help Python · help_session.py
from session import run

# Three ways to read about a command: help for builtins, --help for many programs, man for installed manual pages.
run("""
help type | head -n 2
printf --help 2>&1 | head -n 1
!ls --help
man -w ls
""")

Output

$ help type | head -n 2
type: type [-afptP] name [name ...]
    Display information about command type.
$ printf --help 2>&1 | head -n 1
printf: printf [-v var] format [arguments]
$ ls --help
ls: unrecognized option `--help'
usage: ls [-@ABCFGHILOPRSTUWXabcdefghiklmnopqrstuvwxy1%,] [--color=when] [-D format] [file ...]
[exit status 1]
$ man -w ls
/usr/share/man/man1/ls.1

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 help_session.py

Kind of command Where its documentation is Example
Keyword or builtin help NAME help type, help cd
Installed program man NAME man ls
Many programs and Bash builtins NAME --help printf --help in Bash
The shell itself man bash every keyword, builtin and expansion

Run type -a first when you are unsure: if it says “shell builtin”, use help; if it prints a path, use man.

One habit for an unfamiliar command

Ask type -a NAME, then read the matching help: help for a builtin, man for a program. Try --help last, and read its error if the program does not support it.

Checkpoint

Check: What a name means to Bash · Where to find help

  1. Question 1 of 2 type -a echo prints "echo is a shell builtin" and then "echo is /bin/echo". Which one runs when you type echo hi?

    Choose one answer.

    Show the answer: Question 1 of 2

    Answer: The builtin, because Bash checks builtins before it searches PATH

    type -a lists the matches in the order Bash uses them. The first one, the builtin, is what runs.

  2. Question 2 of 2 type -a cd says "cd is a shell builtin". Where do you read how cd works in Bash?

    Choose one answer.

    Show the answer: Question 2 of 2

    Answer: help cd

    Ask type -a first. A builtin is documented by help; a program with a path by man; many tools also answer --help, but not all.

Practise: read command lines and find their help

Each question gives a command line or a name and asks what Bash makes of it; the wrong answers come from the mistakes above, and each explains itself:

Practice that adapts to you

Practise this lesson

9 questions about 4 ideas of this lesson. Each answer is explained at once, and what you get right is kept in this browser.

  1. Question 1 of 9 What does cat -ne drinks.txt mean?

    Choose one answer.

    Show the answer: Question 1 of 9

    Answer: The same as cat -n -e drinks.txt

    -n numbers the lines and -e marks each line's end with $; written apart or grouped, the output was identical.

  2. Question 2 of 9 How many files does head -n 2 a.txt b.txt read?

    Choose one answer.

    Show the answer: Question 2 of 9

    Answer: Two, a.txt and b.txt

    An option that takes an option-argument reads the next word for it. The words after that are operands.

  3. Question 3 of 9 How do you delete a file named -rf without deleting anything else?

    Choose one answer.

    Show the answer: Question 3 of 9

    Answer: rm -- -rf, or rm ./-rf

    Quoting does not help, because the command still receives a word starting with a dash. Only -- or a leading ./ makes rm read it as an operand.

  4. Question 4 of 9 A cleanup script runs rm * in a folder where users can create files. What should it run instead, and why?

    Choose one answer.

    Show the answer: Question 4 of 9

    Answer: rm -- , or rm ./, so that a file called -rf cannot become options

    ShellCheck reports SC2035 for a bare * in arguments. Use -- * or ./* wherever file names come from a folder you do not control.

  5. Question 5 of 9 In which order does Bash look a command name up, after aliases and keywords?

    Choose one answer.

    Show the answer: Question 5 of 9

    Answer: Functions, then builtins, then the folders of PATH

    A name with no slash is checked as a function, then a builtin, then searched for in PATH. A name that nothing matches ends with "command not found" and status 127.

  6. Question 6 of 9 In the lesson's session, command -v nosuchcmd printed nothing. With what exit status did it end?

    Type a number.

    Show the answer: Question 6 of 9

    Answer: 1 exit status

    command -v prints nothing and returns 1 when a name does not exist, which is why command -v nosuchcmd || echo missing printed "missing".

  7. Question 7 of 9 Someone defines a function named ls in their terminal. What runs when they next type ls, and how can they tell?

    Choose one answer.

    Show the answer: Question 7 of 9

    Answer: The function, because functions come before programs; type -a ls shows the function first

    A function or alias can shadow a program. type -a NAME reveals what the name means to this shell right now.

  8. Question 8 of 9 type -a ls prints "ls is /bin/ls". Which command shows its manual page?

    Choose one answer.

    Show the answer: Question 8 of 9

    Answer: man ls

    A path in type's answer means a program: read man NAME. "shell builtin" means read help NAME.

  9. Question 9 of 9 macOS's ls answered ls --help with "unrecognized option" and exit status 1. What does that show?

    Choose one answer.

    Show the answer: Question 9 of 9

    Answer: Not every program supports --help, so man is the dependable source for programs

    GNU tools and Bash's builtins answer --help; other programs may not. When in doubt, use man for programs and help for builtins.

Interview questions

Warm-up (fresher to 2–5 years): what do -- and command -v do in a script?

-- marks the end of a command’s options: every word after it is an operand, even one that starts with a dash. That protects commands such as rm -- "$file" or cat -- * from file names like -n or -rf, which would otherwise be read as options. command -v NAME prints how the shell would run NAME, a path for a program, the bare name for a builtin or function, or the definition for an alias, and returns status 1 with no output when NAME does not exist. Because POSIX defines it, it is the portable test for “is this command installed?” in a script: if command -v jq >/dev/null; then …. It is preferred to which, a separate program that POSIX does not define.

Two harder questions follow, about a dangerous glob and about a command that runs the wrong program. Work out your answer before you open each first step:

Model answers open with any pass: ₹79 for 1 week ($2.99), one payment that never renews.

  1. Fresher to senior

    A nightly script runs cd /srv/uploads; rm * to empty a folder that users can write to. What can go wrong, and how would you rewrite the line?

    Model answer, Pro. Model answers open with any pass; prices are in the notice on this page. First step and follow-ups

  2. Mid to senior

    On one machine, typing grep runs an old version with different options, although you installed a new one. How do you find out what grep means to your shell, and how do you fix it?

    Model answer, Pro. First step and follow-ups

Flashcards · 6 cards

Recall it, then check

Say the answer to yourself before you look: recalling it is what makes it stick.

  1. Into which parts does the command line head -n 5 notes.txt split?

    The command name head, the option -n, its option-argument 5, and the operand notes.txt, which is what the command works on.

  2. What does -- do in rm -- "$file"?

    It ends the options. Every word after it is an operand, even one that begins with a dash, so a file called -rf is removed as a file and never read as options.

  3. Why can rm * go wrong in a folder that holds a file named -n or -rf?

    The glob hands each name to rm as an ordinary word, so a name starting with a dash is taken as an option. Write rm -- * or rm ./* so every name stays a file.

  4. In which order does Bash resolve a command name?

    Aliases and keywords first, then functions, then builtins, and last the programs it finds through PATH. type -a NAME lists every match in that order.

  5. What is the portable test for whether a command exists?

    command -v NAME. It prints how the shell would run the name: a path for a program, the bare name for a builtin or function, the definition for an alias. When nothing matches it prints nothing and ends with status 1.

  6. Where do you look up a builtin, an installed program and a tool's own options?

    help NAME documents Bash builtins, man NAME opens the manual page of an installed program, and NAME --help prints the option list that many tools carry themselves.

Key takeaways

  • A command line splits into the command name, options, their option-arguments and operands, and one-letter options can be grouped behind one dash.
  • A glob passes file names as ordinary words, so -- or ./* keeps a name such as -n from becoming an option.
  • Bash resolves a name as an alias or keyword first, then as a function, a builtin and finally a program found through PATH, and type -a lists every match in that order.
  • command -v is the portable test for whether a command exists, and help, man and --help document builtins, installed programs and many tools respectively.

Terms in this lesson

builtin
A command that is part of the shell itself rather than a separate program, such as cd, echo or type in Bash. help NAME documents it.
operand
A word after a command's options that the command works on, usually a file name. After --, every word is an operand, even one that starts with a dash.
option
A word that starts with a dash and changes how a command behaves, such as -n for head. One-letter options without values can usually be grouped behind one dash, as in cat -ne.

References

Report a problem with this lesson

Quick answers and tool search

Type to search tools or to get a quick answer, for example 18% of 2500. Use the up and down arrow keys to move through the results, Enter to choose, and Escape to close.