A Beginner’s Guide to the Command Line

If you’re an experienced developer who knows your system inside out, this guide is not for you. However, if you’ve only ever used desktop tools, or you’re just starting out as a developer, you may not have needed to work at what is variously called “the command line”, “a console” or “a terminal”. If these terms are unfamiliar to you, or they kind of ring a bell but you’re not sure what they are, read on!

The macOS Terminal showing the commands introduced below

Computer control

Back in the dim and distant past, computers were controlled with typed commands. Then we evolved the Graphical User Interface (GUI) and typing was superseded by pointing and clicking. That’s how most folks work with computers today, though often they use a finger on a touchscreen rather than a mouse on a desk.

Computers can still be controlled by entering commands on the keyboard and, as you’ll have guessed, this takes place at the command line. Windows, macOS and Linux all have facilities for presenting you with a command line. Typically these applications are called consoles or terminals.

On macOS, for example, the app is literally Terminal. You’ll find it in Applications > Utilities. Different versions of Linux offer different terminal apps, but they’ll be called something like Terminal and be accessible from the desktop. Windows 10 has Windows Terminal; older versions have a Command Prompt entry in the Start menu which calls up their own terminal app. Microsoft also has Windows Subsytem for Linux, which implements a Linux command line in Windows 10.

A terminal is just a presentation mechanism; the software doing the real work is called a “shell”. That’s why you might see PowerShell in your terminal window on a Windows PC. The shell is the real interface between you and the computer; the terminal just displays the shell’s output in a window and sends your key presses to the shell.

If you’ve used a Linux computer that has been configured not to start up a desktop screen, you’ve been using the command line all along and communicated directly with a shell. Terminal apps are generally only used from a GUI’s desktop.

Seasoned developers have favorite shells, but at the start it’s best to make use of the one your operating system provides. Once you’ve got the gist of how it works, and have begun making use of it, you can start to explore the alternatives.

The shell’s prompt

However you invoke a shell, you’ll see what’s called a “prompt”, the shell’s cue to you to type in a command. When the command has completed, you’ll see the prompt appear again: the shell is telling you that it’s ready for its next task.

There are many different shells so you may not alway see the same prompt when you use multiple machines. The most common Linux shell is called Bash; its standard prompt is the $ symbol. macOS recently began using the Z Shell, which uses % as its prompt. On Windows, the prompt is usually a >. Whatever the symbol, and whatever information is displayed alongside it — often the current directory but you might also see the drive letter, the name of the logged in user, or the date — the prompt tells you the shell is waiting for input.

Current directory? This is another common term read in discussions concerning the command line. You might also see it called the “working directory”. “Directory” is just shell-speak for folder, “working” the one you’re currently viewing in the terminal.

Files, directories, and their paths

The sequence of directories in which a file or a directory is located is called its “path”. Here’s a macOS example:


This is an “absolute” path: it identifies precisely where the file is to be found. Linux and macOS use the /symbol, as shown above, to separate files and directories in the path, but Windows uses \ so just replace one with the other in this and the following examples if you’re using Windows Terminal or PowerShell.

Depending on your shell, you may be able to use “relative” paths — paths that depend on where you are starting from. These use the following markers:

  • . — the current directory.
  • .. — a parent directory.

So if we’re working in the directory /Users/Twilio/Documents/websource/ then we can access the script — the .sh file — mentioned above using the relative path:


This means ‘go up to the parent directory’ (ie. Documents/), ‘go up to the next parent directory’ (Twilio/), then ‘go down to GitHub/scripts/’.

If you’re wondering what the / right at the start of the first path is, it’s special: it’s the Linux and macOS “root” directory, ie. the top-most directory from which all others branch.

You may see a ~ (called a tilde) in a path. It’s one of the Unix shells’ shorthand codes: it means the current user’s home directory and you can use it anywhere you might otherwise write your home directory’s path out in full. It’s also a good way of referring to home directories in scripts that will be used by different folks: they all have different home directories, but ~ will be read by the shell as the right one every time.

To run the script, you just provide its name at the prompt. If it’s in a different directory from the one in which you’re working, provide an absolute or relative path. If it’s in the working directory, you can omit the path. However, you will need to tell the shell that the file is here: prefix it with ./ to indicate the current directory:


It’s outside of the scope of this guide, but it’s useful to know that Linux and macOS shells have a variable called $PATH which tells them where to look for files: it contains a list of directory paths. If you type just, the shell will only look for the file in the directories included in $PATH. That’s why we need the ./ above — /Users/Twilio/GitHub/scripts is not listed in $PATH.

When referencing shell variables (though not when setting them), always prefix their names with the $ sign.

Useful commands

If you open up a terminal now, when the prompt appears enter one of the following commands:

Platform Command
macOS/Linux ls
Windows Terminal DIR

These commands tell the shell to list the files and sub-directories within the current directory, also known as the working directory. How can you see what that is? With another command of course:

Platform Command
macOS/Linux pwd
Windows Terminal CHDIR

To create a new directory, use the following command:

Platform Command
macOS/Linux/Windows Terminal mkdir <directory_path>

If the value you put in place of <directory_path> is just the new directory’s name, it will be created in the working directory.

To move or “change” to another directory, use the following commands:

Platform Command
macOS/Linux cd <directory_path>
Windows Terminal CHDIR <directory_path>

There are literally dozens of commands you can enter, far too many to list here. There are lots of online resources that list them — just use your favorite search engine.

Arguments: information for commands

Most commands are more than a simple word — you can provide extra information in the form of “arguments” placed after the command and separated by at least one space. Arguments might include target filenames or the location of the directory where the command’s results will be placed.

The need to separate arguments with spaces means you need to take care with file and directory names that contain spaces. Telling a shell to treat included spaces as part of an argument and not a separator is called “quoting”. For example, to stop the second space in the command

cat /Users/Twilio/my file.txt 

from causing errors (specifically cat: /Users/Twilio/my: no such file or directory and cat: file.txt: no such file or directory), you wrap the argument in quotes:

cat "/Users/Twilio/my file.txt" 

This correctly display the contents of the named file.

Other arguments govern how the command works: they’re called “switches”, “flags” or “options” and are prefixed with - or --. For example, you might issue the ls command mentioned above with these two switches:

ls -l -a

Respectively, these cause ls to output its list in columns (-l) and to include hidden files (-a). The ls command allows you to combine switches into a single statement:

ls -la

This has the same effect as the previous example, but is more compact. Many commands work this way, but not all do. Many commands have the switches -h and/or --help which will cause them to output guidance — these will tell you if the command supports combining switches and flags this way.

Remember the mkdir command we mentioned earlier? If you provide a full path as an argument and that includes directories that don’t exist, mkdirwill display an error message. However, if you also include the -p switch, mkdir will also create any ‘missing’ directories within the path.

Shell scripts

Some shell commands are built into the shell itself, but many more are programs in their own right. Others are “shell scripts”. These are what make the command line so attractive to developers. Scripts are a way to combine multiple commands with variables and flow logic to automate key tasks.

Here’s an example: if you’re building a website, you might write a script to automate all the repetitive setup work you need to do when you test a change: process the style sheets, minify your CSS and JavaScript files, organize the content and transfer it to the location from which it will be served, and to start up the HTTP server.

Or you might write a script to extract certain data points from a stack of log files. Or to package apps ready for distribution. Or... well, the options are endless. Shell scripting is a truly powerful way of automating processes.

A sample script

Let’s look at the first example. Here’s the code:

# Rebuild Hugo-generated website 2.3.1

# Set variables

# Move to source directory
cd "$source" || exit 1

# Zap any existing build
rm -rf public

# Generate CSS

# Build the site
if hugo; then
    cd public
    rm $(find . -name .DS_Store)
    gsutil rsync -d -R . gs://

Most lines in a script are read and handled as if you’d keyed in at the prompt; a couple of others determine how the script is run, delimit code structures, or are comments. You can spot all the comment lines: they start with # — shells ignore any text after that symbol, up to the end of the line. Let’s go through the rest.

The first real line sets the value of a new variable, source. Don’t read the quote marks as string delimiters — they’re being used for quoting. Why? Because the value of the variable GIT may contain spaces and we want the shell to handle them correctly. GIT is a variable set outside of the script; to read it back we prefix it with $, as we do when we later read back source. Not including spaces on either side of the assignment operator, =, is a requirement in shell scripting.

The command cd we know already: it makes the named directory (the value of source) the current directory. The || symbol stands for ‘logical OR’ and essentially tells the shell to check the outcome of command and, if it failed, to run the rest of the line. In this case, that means we exit the script with an exit code of 1, i.e., a failure. The exit code for success is 0. Why check? Because if the target directory doesn’t exist, we want to make sure we don’t continue.

The command rm is short for ‘remove” — it deletes the named file or directory. Because public is a directory (which we might have made earlier), we need to include the switches -f and -r to force rm to delete the folder if it contains any files and to go into and directories it contains and delete them too. You’ll need -r whenever you rm a directory.

Remember, lines in a script are processed as if they were entered at the prompt. "$source/scripts/css" just runs the named script, css, to prepare the sites style sheets.

The last section shows some control logic: the script runs the program hugo and if the program runs successfully — its exit code is 0 — the lines inside the if... fi structure are executed.

If hugo runs successfully — it’s a static website builder — the script switches to the public directory (hugo is responsible for creating this) and then removes some files that may have been copied in but which we don’t want. The $(...) formatting tells the shell to run the code in the brackets and return whatever that code outputs. The output, which is either nothing or a list of files, is passed to rm as an argument — the files we want deleted. The find command is passed . to tell it to look in the current directory; the -name flag and its value, .DS_Store, tell find to look for files of that name.

Finally, we call Google’s gsutil tool with a number of arguments to sync the contents of public, ie. the build website files, with a Google Cloud Platform web server.

And we’re done — we’ve build our static website and synced any new files with the web server!

If the script is called, we run it, as we saw before, by entering ./ at the prompt. If you’d just created this script in a text editor, you’d first need to make it executable — for which you use the chmod command and its +x (for ‘add execute permission’) argument :

chmod +x

Where to learn more

We’ve really just scratched the surface of the command line, shells and scripts. Hopefully, you now understand what these terms mean, and why developers make them key components of their toolkits. You may already be thinking about how you can do the same.

To learn more about specific commands, Linux and macOS provide a shell-accessible command called man which you provide a command as an argument. It will output the “manual” for the specified command — hence the name. Use the arrow keys to move up and down through the text, and hit Q to quit.

The Linux Documentation Project has a great guide to getting started with the Bash shell and a more detailed guide covering advanced scripting. There is also the Bash Manual.

For Mac users, there’s an equivalent manual for the Z Shell. Check out Apple’s Terminal User Guide too.

Microsoft has its own guides for Windows Terminal, PowerShell, and Windows Subsystem for Linux.

We can’t wait to see what you script!

Tony Smith
Rate this page:

Need some help?

We all do sometimes; code is hard. Get help now from our support team, or lean on the wisdom of the crowd browsing the Twilio tag on Stack Overflow.

Thank you for your feedback!

We are always striving to improve our documentation quality, and your feedback is valuable to us. How could this documentation serve you better?

Sending your feedback...
🎉 Thank you for your feedback!
Something went wrong. Please try again.

Thanks for your feedback!

Refer us and get $10 in 3 simple steps!

Step 1

Get link

Get a free personal referral link here

Step 2

Give $10

Your user signs up and upgrade using link

Step 3

Get $10

1,250 free SMSes
OR 1,000 free voice mins
OR 12,000 chats
OR more