The Terminal#
Note
Source: Contributed by PhD students in COMP 501 at Loyola University Chicago.
Throughout this course you have been running Python programs by clicking a “Run” button in an IDE or executing code in an interactive shell. Now we explore another powerful way to interact with your programs: the terminal.
The terminal may seem intimidating at first — a text-based window with no buttons to click. But it is one of the most important tools in a programmer’s toolkit, and learning to use it will make you more capable as a developer.
Terminal vs. Shell#
People often use “terminal” and “shell” interchangeably, but they refer to different things.
Terminal (or terminal emulator) — the window on your screen where text appears. On macOS this is the Terminal app; on Windows, Command Prompt or PowerShell; on Linux, GNOME Terminal or similar.
Shell — the program running inside the terminal that reads your commands and tells the operating system to execute them. Common shells include
bash,zsh,fish, and PowerShell.
Think of it this way: the terminal is the video-call window (Zoom, Teams) — just the frame. The shell is the person you are talking to — the part that actually understands and responds.
Why Programmers Use the Terminal#
Even though graphical interfaces are available, experienced programmers often prefer the terminal for several reasons:
Speed — typing a command is faster than navigating menus. Renaming 100 files with a graphical interface means 100 click-rename cycles; with the terminal, a single command handles all of them at once.
Precision — you can express exactly what you want, with no ambiguity.
Automation — sequences of commands can be saved in scripts and run automatically, including your Python programs.
Remote work — the terminal works the same whether you are on your laptop or connected to a server on the other side of the world.
Universal skill — terminal commands are similar or identical across operating systems; learning them once pays dividends everywhere.
Opening Your Terminal#
macOS: Press Command + Space, type Terminal, press Enter. Or find it
in Applications > Utilities > Terminal.
Windows: Press the Windows key, type PowerShell or cmd, press Enter.
Linux: Press Ctrl + Alt + T on most distributions.
When the terminal opens you will see a prompt — the shell’s signal that it is
ready for a command. The prompt typically ends with $ on macOS/Linux or >
on Windows.
Essential Commands#
pwd — print working directory#
Shows your current location in the file system.
$ pwd
/Users/yourname/Documents
ls — list contents#
Shows what is in your current directory (use dir on Windows Command Prompt).
$ ls
homework.txt python_projects essay.docx
cd — change directory#
Moves you to a different directory.
cd python_projects # move into a subdirectory
cd .. # move up one level
cd ~ # move to your home directory
mkdir — make directory#
Creates a new directory. In the terminal, no news is good news — if the command succeeds, you just get the prompt back.
mkdir my_project
whoami — show current user#
Prints your account name — useful when you are working on a shared system or switching between users:
$ whoami
yourname
cat — display file contents#
Prints the contents of a file to the terminal. You can view one file or several at once.
$ cat notes.txt
$ cat file1.txt file2.txt
touch — create empty files#
Creates one or more empty files. If the file already exists, touch updates its
timestamp without changing the contents.
$ touch hello.py
$ touch file1.py file2.py file3.py
cp — copy files and directories#
Copies a file to a new location. Use -r (recursive) to copy an entire directory.
$ cp notes.txt notes_backup.txt
$ cp -r my_project my_project_backup
mv — move or rename#
Moves a file to a different location, or renames it when the destination is in the same directory.
$ mv old_name.py new_name.py
$ mv script.py ~/Documents/
rm — remove files and directories#
Deletes a file permanently — there is no Recycle Bin from the terminal. Use -r
to remove a directory and everything inside it.
$ rm temp.txt
$ rm -r old_project
echo — print text#
Prints a message to the terminal. Frequently used in scripts and to inspect variable values.
$ echo "Hello, world!"
$ echo "Current user: $USER"
less — page through a file#
Opens a file one screen at a time. Press Space to advance, b to go back,
and q to quit. Unlike cat, less is comfortable for long files.
$ less long_file.txt
grep — search text#
Searches for a pattern inside a file and prints matching lines. grep is one of
the most useful commands for exploring code and log files.
$ grep "def " my_script.py
$ grep -i "error" server.log
The -i flag makes the search case-insensitive.
find — locate files by name or property#
Searches a directory tree for files matching criteria such as name, size, or modification date.
$ find . -name "*.py"
$ find ~/Documents -name "report.txt"
File Permissions#
Every file on a Unix-like system has an owner and a set of permissions that control who may read, write, or execute it.
chmod — change permissions#
The numeric mode 755 means the owner can read, write, and execute; everyone else
can read and execute.
$ chmod 755 my_script.py
chown — change ownership#
Transfers ownership of a file to a different user or group. This is most commonly needed on shared servers.
$ chown alice:staff my_script.py
Process Management#
A process is a running program. The terminal gives you tools to observe and control processes.
ps — list running processes#
Shows a snapshot of the processes currently running in your terminal session.
$ ps
top — live process monitor#
Displays all processes in real time, sorted by CPU usage. Press q to quit.
$ top
kill — terminate a process#
Sends a signal to a process, usually to stop it. Replace PID with the numeric
process ID shown by ps or top.
$ kill 1234
Standard Streams#
When a program runs, it communicates through three standard channels:
stdin (standard input) — where the program reads input. When you type into a running program, it comes through stdin.
stdout (standard output) — where the program sends normal output. Python’s
print()writes to stdout.stderr (standard error) — where the program sends error messages. Having a separate channel for errors lets you handle them independently from normal output.
User Input → [stdin] → Your Program → [stdout] → Normal Output
↳ [stderr] → Error Messages
Here is a Python script that writes to all three:
import sys
print("This goes to stdout")
sys.stdout.write("This also goes to stdout\n")
sys.stderr.write("This goes to stderr\n")
user_input = input("Type something: ")
print(f"You typed: {user_input}")
Command Redirection#
Standard streams can be connected to files and to other commands. This is called redirection. Redirection is one reason terminal commands are so powerful: a command does not need to know whether its input came from the keyboard, a file, or another program.
The most common redirection operators are:
Operator |
Meaning |
|---|---|
|
Send stdout to a file, replacing the file if it already exists. |
|
Send stdout to a file, appending to the end if it already exists. |
|
Read stdin from a file instead of the keyboard. |
|
Send stderr to a file. |
|
Send stdout from one command into stdin of another command. |
Using a Pipe#
The vertical bar symbol, |, is called a pipe. It connects the output of
one command to the input of another command.
For example, to check whether a file called hello.py appears in the current
directory, send the output of ls into grep:
$ ls | grep hello.py
If hello.py exists, its name is printed. If it does not exist, nothing is
printed. The ls command writes a list of filenames to stdout; grep reads
that list from stdin and prints only matching lines.
Writing Output to a File#
The > operator sends stdout to a file. This makes it possible to create a
short file without opening an editor:
$ echo 'print("Hello, world!")' > hello.py
The outer single quotes protect the inner double quotes, so the shell passes the
Python statement to echo as one piece of text. After running the command,
hello.py contains:
print("Hello, world!")
You can run the new program immediately:
$ python hello.py
Hello, world!
Be careful with >. If the file already exists, the shell replaces its
contents. Use >> when you want to append instead:
$ echo 'print("Goodbye!")' >> hello.py
Reading Input from a File#
The < operator sends a file into a program’s stdin. Suppose
name_reader.py contains:
name = input("Name: ")
print(f"Hello, {name}!")
Create a small input file:
$ echo "Ada" > name.txt
Then run the program with stdin redirected from the file:
$ python name_reader.py < name.txt
Name: Hello, Ada!
The program still calls input(), but the input comes from name.txt
instead of the keyboard.
Capturing Error Messages#
Because stderr is separate from stdout, you can save error messages without
mixing them with normal output. The 2> operator redirects stderr:
$ python missing_file.py 2> errors.txt
If the program prints a traceback or another error message, that message is
written to errors.txt. Normal output still appears in the terminal unless
you redirect stdout too.
Creating Several Lines with a Here Document#
A here document lets you provide several lines of text to a command. The
cat command normally copies stdin to stdout. Combined with >, it can
create a short Python file:
$ cat > channels.py <<'END'
import sys
print("This goes to stdout")
sys.stdout.write("This also goes to stdout\\n")
sys.stderr.write("This goes to stderr\\n")
user_input = input("Type something: ")
print(f"You typed: {user_input}")
END
The word END marks where the input stops. It is not written into the file.
Quoting it as 'END' tells the shell not to interpret special characters
inside the text.
This technique is useful for creating very small programs before you have learned a terminal editor such as Vim or Emacs. For larger programs, use a real editor so you can revise the file safely.
Running Python Scripts from the Terminal#
Create a file called hello_terminal.py:
print("Hello from the terminal!")
print("This script is running successfully.")
Then run it:
python hello_terminal.py
(Use python3 if your system requires it.)
Exit Codes#
When a program ends it reports an exit code back to the shell:
0means success.Any non-zero value means failure.
import sys
choice = input("Should this program succeed? (yes/no): ")
if choice.lower() == "yes":
print("Success!")
sys.exit(0)
else:
print("Failure!")
sys.exit(1)
Check the exit code after running:
# macOS/Linux
echo $?
# Windows PowerShell
echo $LASTEXITCODE
Command Line Arguments with sys.argv#
Sometimes you want to give a program information before it starts running. Python’s
sys.argv is a list that holds:
sys.argv[0]— the script namesys.argv[1],sys.argv[2], … — any extra words typed after the script name
import sys
print("Arguments:", sys.argv)
for i, arg in enumerate(sys.argv):
print(f"Argument {i}: {arg}")
Run it:
python show_arguments.py hello world 123
Output:
Arguments: ['show_arguments.py', 'hello', 'world', '123']
Argument 0: show_arguments.py
Argument 1: hello
Argument 2: world
Argument 3: 123
Here is a script that uses sys.argv to greet a user:
import sys
if len(sys.argv) < 2:
print("Error: please provide your name.")
print("Usage: python greet.py YourName")
sys.exit(1)
name = sys.argv[1]
print(f"Hello, {name}!")
sys.exit(0)
Professional CLI Programs with argparse#
sys.argv is simple but limited — it provides no automatic help, no validation,
and no support for optional flags. Python’s argparse module solves all of this.
import argparse
def main() -> int:
parser = argparse.ArgumentParser(description="A friendly greeting program")
parser.add_argument("name", help="Your name")
parser.add_argument("-n", "--number", type=int, default=1,
help="Number of times to greet (default: 1)")
args = parser.parse_args()
for _ in range(args.number):
print(f"Hello, {args.name}!")
return 0
if __name__ == "__main__":
raise SystemExit(main())
Try:
python greet_argparse.py Alice
python greet_argparse.py Alice -n 5
python greet_argparse.py --help
argparse automatically generates a --help message that lists all arguments,
their types, and their descriptions — essential for any tool that others will use.
Here is a more complete example — a file search tool:
import argparse
import sys
def search_file(filename: str, keyword: str,
case_sensitive: bool = True,
line_numbers: bool = False) -> int:
try:
with open(filename, "r") as f:
for line_num, line in enumerate(f, start=1):
haystack = line if case_sensitive else line.lower()
needle = keyword if case_sensitive else keyword.lower()
if needle in haystack:
if line_numbers:
print(f"{line_num}: {line.rstrip()}")
else:
print(line.rstrip())
return 0
except FileNotFoundError:
print(f"Error: '{filename}' not found", file=sys.stderr)
return 1
except PermissionError:
print(f"Error: permission denied for '{filename}'", file=sys.stderr)
return 1
def main() -> int:
parser = argparse.ArgumentParser(
description="Search for a keyword in a text file",
epilog="Example: python search_file.py data.txt Python -i -n"
)
parser.add_argument("filename", help="Path to the file to search")
parser.add_argument("keyword", help="Keyword to search for")
parser.add_argument("-i", "--ignore-case", action="store_true",
help="Case-insensitive search")
parser.add_argument("-n", "--line-numbers", action="store_true",
help="Show line numbers in output")
args = parser.parse_args()
return search_file(
args.filename,
args.keyword,
case_sensitive=not args.ignore_case,
line_numbers=args.line_numbers,
)
if __name__ == "__main__":
sys.exit(main())
Try:
python search_file.py story.txt dragon
python search_file.py story.txt dragon -i
python search_file.py story.txt dragon -i -n
python search_file.py --help
Exercises#
Open your terminal and run
pwd,ls, andwhoami. What do they tell you?Create a directory called
practice, move into it, create two subdirectories inside it, and then navigate back to the parent.Write a script
greet.pythat takes a name as a command line argument and printsHello, <name>!. Exit with code1if no name is provided.Extend the script using
argparseto also accept an optional--timesflag that controls how many times the greeting is printed.Write a script
process_numbers.pythat:Accepts one or more numbers as positional arguments.
Supports optional flags
--sum,--average,--max, and--min.Uses
argparseand exits with a non-zero code if any argument is not a valid number.