The Command Line is Your Best Friend

The command line can either be your best friend, or your worst enemy. It simply depends on how you use it, and what you use it for. If you're one of the many people who cringe at the mere thought of using the command line, then you've come to the right place!


Command Line Interface?

Yes, it's that white (or green) on black screen, where mysterious text flows and strange commands execute. I know great programmers who never use the CLI; however, I also know basic computer users who do everything in the CLI instead of the graphical user interface (GUI). They have console applications to browse the web and file system, read mail, view images and edit text. They even watch YouTube videos and read PDF files without a GUI!

It's up to each person to find his or her best workflow. Some prefer the GUI, while others enjoy the CLI.

Please Note: The real CLI has little or nothing to do with what you see on TV. Rarely is the CLI realistically portrayed in movies or TV shows.


Terminology

Newcomers to the Unix/Linux world are typically confused, when it comes to the difference between a terminal, a console and a shell.

From the user's perspective, there may be little to no difference between them, but in actuality, the the user uses a console to connect to a terminal, in order to look at the shell running on the computer.

It's up to each person to find his or her best workflow.

In ye olden days, these three items were separate hardware. The console was nothing more than a monitor and keyboard; it had no computing capabilities. It connected to a terminal, via a serial interface, the most common being the RS-232 connector.

A terminal is akin to an end-point to a mainframe. It usually had some computing capabilities and could communicate over a network, or some form of specialized connection, to a mainframe. A terminal also provided administrative rights to the system, which was why it was usually kept in a closed room. The consoles from the employees' area connected to these terminals, allowing them to work without having administrative access to the mainframe.

Consoles and terminals eventually merged in a single device, the most notorious being the VT terminals emulated in modern Linux distributions.

The shell is the actual program capable of reading the user's input and providing the result on the screen. A shell can be textual (like the CLI) or graphical (like Windows' GUI). In today's computing, a shell is much more than a simple interface between the user and system. It is responsible for managing processes, windows, applications, commands and other aspects of the system.

The CLI is a shell that offers a text-based interface to the user.

The shell interprets the commands entered through the command line, and a user can combine multiple commands into a single script. Modern shells have a scripting language of their own, providing the ability to perform complex decisions.

Most modern Linux distributions, as well as Mac OSX, use a shell, called BASH. Solaris and OpenIndiana use KornShell by default, which is another variant of BASH. Please note that this tutorial will focus on BASH.

Windows users can also use BASH. It is distributed with Cygwin and MinGW.


Let's Talk About BASH

Most modern Linux distributions, as well as Mac OSX, use a shell, called BASH.

BASH stands for Bourne Again Shell. It was released in 1989 as a reincarnation of the Bourne Shell, the then default shell on Unix systems. It was programmed by Stephen Bourne and came as a replacement for Thompson Shell, the first ever shell software for UNIX. The old Bourne Shell is still present in some Unix systems. You can usually find it as /bin/sh. However, even that has been replaced by BASH on most modern distributions; both /bin/sh and /bin/bash are executables for BASH.

The BASH Prompt

The one thing that you will always have is BASH's prompt. It is a story in and of itself, and we could spend this entire tutorial on how to configure and personalize it. Instead, we'll only discuss the basics in this tutorial.

This is what my prompt looks like. The first word, csaba is my username, followed by @ and my computer's hostname, and then the current folder. The character "~" stands for the current user's home directory - /home/csaba, in my case. The line ends with $. Whatever I type after the $ is the command that I want my shell to execute.

Root is Special: If you are root, the prompt ends with # instead of $.

Of course, this is only a simple example; you can put a lot more information in your prompt line. Let's explore some basic examples.

BASH has a set of special variables, PS1, PS2, PS3 and PS4, which control the contents in the prompt at different stages of a program's execution. We will only talk about PS1 in this tutorial. You can check what the PS1 variable contains with the following command:

What you see here is my prompt, followed by a command echo $PS1 and the output of the command. In BASH, you put the dollar sign before the variable name when you want to read its contents. The echo command simply outputs whatever it receives as a parameter. If the parameter is a variable, its value displays on the screen.

The output represents a format. \[\033[01;32m\] is a color code for green, and \u represents the current user's username. The \h token stands for hostname, and \[\033[01;34m\] is the color code for blue. \w is the current directory, and \[\033[00m\] is a light gray color for whatever follows (the commands I type). Below is a screenshot, so that you can better visualize the result.

There are special characters preceded by "\" that have their own special meaning. Otherwise, "\" denotes an escape character for what follows (as in the color codes). Below is the complete list of special characters that you can use in the BASH prompt, cited from the official BASH manual:

  • \a - an ASCII bell character (07)
  • \d - the date in "Weekday Month Date" format (e.g., "Tue May 26")
  • \D{format} - the format is passed to strftime(3) and the result is inserted into the prompt string; an empty format results in a locale-specific time representation. The braces are required
  • \e - an ASCII escape character (033)
  • \h - the hostname up to the first `.'
  • \H - the hostname
  • \j - the number of jobs currently managed by the shell
  • \l - the basename of the shell's terminal device name
  • \n - newline
  • \r - carriage return
  • Each of these commands are capable of much more than what I covered in this tutorial.

  • \s - the name of the shell, the basename of $0 (the portion following the final slash)
  • \T - the current time in 12-hour HH:MM:SS format
  • \t - the current time in 24-hour HH:MM:SS format
  • \@ - the current time in 12-hour am/pm format
  • \A - the current time in 24-hour HH:MM format
  • \u - the username of the current user
  • \v - the version of bash (e.g., 2.00)
  • \V - the release of bash, version + patch level (e.g., 2.00.0)
  • \w - the current working directory, with $HOME abbreviated with a tilde (uses the value of the PROMPT_DIRTRIM variable)
  • \W - the basename of the current working directory, with $HOME abbreviated with a tilde
  • \! - the history number of this command
  • \# - the command number of this command
  • \$ - if the effective UID is 0, a #, otherwise a $
  • \nnn - the character corresponding to the octal number nnn
  • \\ - a backslash
  • \[ - begin a sequence of non-printing characters, which could be used to embed a terminal control sequence into the prompt
  • \] - end a sequence of non-printing characters

Working with Directories and Files

The things everyone must do in a command line environment is navigate the file system, create, delete, copy and move file system objects, and execute commands. This may be common knowledge to some of you, but let's take a quick look:

A line-by-line explanation:

If you are root, the prompt ends with # instead of $.

  1. Create a directory called NetTuts under /home/csaba/tmp.
  2. Change current directory to the newly created directory.
  3. Create a directory called "AnotherDir" inside the current directory.
  4. Create a directory called "SecondDir" inside the current directory.
  5. Create two empty files inside "SecondDir" using the touch command.
  6. Change current directory to SecondDir.
  7. Use pushd to change directory to ~/tmp/NetTuts in order to put our current directory on a stack.
  8. List all files in ~/tmp/NetTuts
  9. Return to our previous directory by issuing a popd command, which fetches (and removes) the top directory from the stack.
  10. List again the contents and see the two files we created a few steps above.

Of course, you have an almighty file manager for the command line, called Midnight Commander. Just execute the mc commdn to start using it. It also has a built-in text editor (with code highlighting) for a large number of languages, as well as smart indentation and other features. It's not a full blown editor, in fact it's a rather simple tool for simple and quick edits. You can simply select any file and hit F4, or you can open a file directly in the editor without starting mc.


Input/Output

Every command must communicate with the command line environment. Commands need input and provide output. Standard Input refers to source from where a command can read information. This is the keyboard by default, and it's frequently referred to as "stdin". Standard Output refers to the place where a command's output will be sent. By default, this is the current console, and its usually referred to as "stdout". Standard Error refers to the place where a command outputs its errors. This is the current console by default, and many refer to it as "stderr".

What we defined so far simply states that a command can read from the keyboard and output its results, both good and bad, to the screen.

In Unix (and similar systems) everything is a file. Your keyboard is a file, your mouse is a file, your screen is a file, programs are in files, text is in files, etc.

A File Descriptor is an integer that the operating system's kernel uses to reference open files. Every system has at least three file descriptors:

  • Descriptor no. 0 - standard input.
  • Descriptor no. 1 - standard output.
  • Descriptor no. 2 - standard error.

Redirections

Unix systems have a very powerful feature: because everything is a file, you can reference and redirect everything from one place to another. The redirection operators are < for stdin and > for stdout. So, if you want a command to read information from the keyboard, you can do something like this:

But what if you want your command to read from a file? Well you can redirect a file into its stdin, like this:

If you want your command's output to go into a file, you can use the > operator. For example we've seen how to list files in a folder:

You can send that result to a file with the following command:

The contents of ThirdFile is:

Let's say we want to navigate to the parent folder, list all its files, and use a command to append the list to the existing file. The > operator redirects output to a file and overwrites that file; so we can't use it. We can, however, use >> (a double >) to append new data to an existing file.

And our file's content is:

Input/Output Redirections

We can combine our knowledge and redirect stderr, stdin and stdout in different ways. In fact the commands below are doing the same thing:

In the second command, we specified the source as standard output (1>) right before the redirection. Please also note that there is no space between 1 and >. In fact, placing a space between the two characters makes 1 a parameter and > would automatically imply redirection of standard output. The two expressions below do the same thing and are different from the ones above:

Of course, these result in an error: "ls: cannot access 1: No such file or directory" - unless you really have a directory named 1. This makes us wonder about the next steps we can take: redirecting errors.

As you can see, the first command outputs stderr in the console and redirects stdout to a file. The result of the first command is an empty file and a message on the screen. The second command, however, redirects the errors to our file. The result is that if there were any outputs on standard output, they would go on the screen and errors would go to the file.

A Real Life Example for I/O Redirection

You basically have two options when you need to search for files in the console. The first is the locate command. It is usually, but not necessarily, installed on many modern Linux distributions. The updatedb command indexes your files and locate uses that database to find your files. It does not actually do a real-time search, it simply looks up indexes in a database. That's why this application is usually scheduled for a daily updatedb.

The second command is called, well, find.

This command performs a real-time search. It is more accurate than locate, but is obviously much slower. Let's play with it a little:

I printed the two ls commands so that you can see the directory structure. The third command is our find. It has a complex parameter system that I will not detail here, but the above example demonstrates the most common use of find. The first parameter, ., is the directory in which we want to search.

Tip: . refers to the current directory. .. refers to the parent directory.

The second parameter we used for find was -name, followed by a file's name. We can use ? and * in the -name parameter to broaden our search:

? stands for any single character, and * refers to any number of any characters.

Next, we will create a directory and make it unreadable by our user. We have not yet reviewed permissions, but don't worry, we will shortly. For now, simply try the following:

I wanted you to not have permission to a directory so that I can demonstrate what find outputs in this case. It tries to access all the directories and search for files that match the given pattern. When it can't access a directory, it outputs a message. This is OK when you have one or two messages, but try to search for something starting from the root folder as an ordinary user. You will get hundreds of such error messages and probably only one or two search results. You don't want to miss the results; you want to get rid of the error messages.

We redirected stderr into /dev/null. This points to... well nothing. Whatever you throw into /dev/null will simply vanish. It is common practice to send errors there when you don't want to see them. If you prefer your results in a file, and your errors sent to /dev/null, you can use multiple redirections:

As you can see, this command outputs nothing to the screen because both errors and standard output are sent to different files. But what if you want both in the same file? Well, you can send stderr into stdout and then send stdout to a file:

Redirections are interpreted from right to left. So the first one that happens is 2>&1, which redirects standard error to standard output. Then 1>./SecondDir/ThirdFile redirects standard output (with the errors already in it) into the specified file.


Let's Talk About Permissions

The permissions discussed in this tutorial are applicable to *nix operating systems. I am not that familiar with the latest Windows versions, but Microsoft uses a different concept for permissions on their file systems.

Users and Groups

There can be several users on the same computer. In fact, several applications register their own special user and use it to run the program in a restricted environment. Each user can be identified by their name and/or their ID, also known as UID.

You can find the list of the currently existing users in the file /etc/passwd.

Groups are listed in the file /etc/group. A group has a name and ID (known as GID), and a group is a container of zero or more users. Each user usually has at least one corresponding group, which has the same name as the user.

The Owner

Files have owners, and the user that creates a file is, by default, its owner. Directories are just special files, and they have the same owner and permission rules as ordinary files.

In our ls -al command, the owner of each result is specified as "user group" ("csaba csaba" in our example). We will now change the owner of AnotherDir with the following:

The chown command means "change owner", and it has a simple syntax: chown user:group path. A user can only change the group ownership to one of the groups it is a member of, and an ordinary user cannot change ownership to another user it cannot access. Of course, a user with administrative privileges, such as "root", can change the ownership of any file and set it to any user and group.

There are three types of file permissions:

  • r - read
  • w - write
  • x - execute

Please Note: The contents of a directory can be listed, if it has execute permissions.

Refer to the previous ls command example. The permissions for each file system object are displayed at the beginning of each line (those rwx characters). Each permission can be set (thus marked with a letter) or not set (marked with a dash: "-").

The three permission types are applied to three categories:

  • User - the rights for the owner user.
  • Group - the permissions for the owner group
  • Others - the permissions for other users attempting to access our file or folder.

The directory called ThirdDir has no permissions, so not even its owner can access it.

But its owner does have the rights to change its permissions:

The chmod command sets global permissions on a file system object, and its syntax is: chmod +/-rights path. Using a + means you enable a right, and - means you remove a right. You can specify any combination of rights. In the previous example, we added read, write and execute permissions to ThirdDir.

Please Note: Read and execute permissions defined this way are applied to owner, group and others. Write permissions are applied only to the current user.

In this second example, we selectively enabled read permissions, removed write permissions and left execute permissions untouched.

But at some point, everything in computing comes down to a binary string. The chown command allows you to easily specify permissions using a decimal representation of the binary permissions.

  • rwx: Each bit is set to 1: 111. Which in decimal is 7.
  • rw-: Is represented as 110. Which in decimal is 6.
  • r-x: Is represented as 101. Which in decimal is 5.
  • r--: Is represented as 100. Which in decimal is 4.
  • -wx: Is represented as 011. Which in decimal is 3.
  • -w-: Is represented as 010. Which in decimal is 2.
  • --x: Is represented as 001. Which in decimal is 1.
  • ---: Is represented as 000. Which in decimal is 0.

The chown command can accept a string of three numbers between 0 and 7. Each digit represents the rights for a specific category in order: user, group, others.

This command sets read, write and execute rights for the owner, read, write, and not-execute for the group, and read, execute, and not-write for others.


The Cat, Sed, and Pipe

Here are a few of the most useful commands.

Cat

This command lets you read the contents of a file. Simply provide the filename as a parameter, and it outputs the file's contents to stdout.

Grep

Grep searches for a pattern and outputs the matching lines. You can optionally specify a file to search as the third parameter:

Adding the --color option highlights the matched word in the the resulting lines.

Pipe

The pipe is represented by the | character; it takes one command's output and feeds it to a second command. This may sound simple, but it's a huge thing. That single character has tens of thousands of lines of code behind it so that you can do this:

This actually runs the cat command, and instead of outputing the results to stdout, it feeds that output to grep. The grep command uses that data and searches for the string "Another". The result is identical to our previous example.

The History of UNIX: This is an old video from AT&T. It is a great video, but scroll to 4:56, if you are only interested in the PIPEs.

Sed

The sed command allows you to execute regular expressions on its input. It can read from a file or be used in a piped command. It outputs the result to stdout.

This example adds a sed to our previous command. With the help of sed, we replaced the string "AnotherFile" with "MyFile" in the output of the cat...grep. Pretty cool, right?

The sed command can accept several parameters. Specifying the -e argument executes the regular expression on its input. If you are not familiar with regular expressions, check out these other Nettuts+ tutorials: Introducing "Regular Expressions: Up and Running" or Regular Expressions Cheat Sheets.


Defining Your Own Commands

Let's imagine that you execute the following ssh connection command frequently:

You can shorten this by creating a custom command, say sshcon. You could create your own commands by using an alias. Alias syntax is in the form of: alias shorthand='original_command'.

Running sshcon executes the more complicated ssh command. But aliases are temporary; they're forgotten when you log out. One possible solution is to edit your .bashrc file.

.bashrc and .bash.profile

The .bashrc file is usually located in your home directory. This file lets you specify any command(s) you want to execute whenever you open a console or log into a shell. Let's add the aforementioned sshcon alias to this file.

Add your code to the end of the file, hit F2 to save the file, and then ESC twice to close the file. Press CTRL+D to log out from the shell. Open another shell and try your alias command. Voila.

Some operating systems, such as Solaris, may not have a ~/.bashrc file. In this case, you can do your magic by editing ~/.bash_profile. In fact, ~/.bash_profile is always present on all systems.

The Hidden Files: Files that begin with a dot (.) denote a hidden file.


A Little Networking

Let's play with the network a little.

Ping

The ping command is an easy way to check if a server is up and accessible.

Its syntax is easy: ping IP_address_or_name. If the server is accessible, you will see a list of reply lines with details. If it's not, an error message states the problem.

Traceroute

The traceroute command displays the route a packet takes from your computer to the destination device.

Routing Table

Both *nix and Windows have a route command. And despite their slight differences in syntax, their functionality is basically the same. This command allows us to see the current routing table of the system, and if necessary, add/delete static routes.

The first column is the destination, the target of a network connection or communication. The term "default" means anything not matched by something else or sent here. Loopback is our virtual local device, the one having the IP 127.0.0.1. This IP always refers to the local, machine and it is present on all operating systems ([ed] there's no place like 127.0.0.1).

The second column is the gateway the connection uses to reach its destination. The first line displays my default gateway as 192.168.111.1. The second line for loopback goes to localhost, and the third line goes to *, no gateway is necessary for acessing our own network.

The third interesting thing here is the last column: "Iface". It specifies the interface used to communicate to the specific destination. In our example, loopback communication goes over the loopback interface lo. Everything else goes through the eno1 interface.

Tip: If you find no route command, try using netstat -nr. It should produce similar output.

Network Configuration

If you want a quick glance at your network configuration, just type ifconfig in the command line.

There is a lot of information here. First, we have two sections, each for a network adapter. My wired network card is called eno1 on my system. You may see things like e1000g0, eth0, en0 or other names. Wireless network devices usually (but not always) begin with a "w".

On the same line is the current status of the interface. In this example, the interface is up, broadcasting, running, etc. The second line is for the IPv4 IP address, netmask and broadcast. The third line is very similar but for IPv6. The forth line, starting with "ether", is the MAC address of the network card, and the remaining lines display data transfer statistics.

Current Network Connections

Another useful command is netstat. It can list all the network connections to the system, as well as the IPs, interfaces and ports the system listens on. Here is a part of netstat's output on my system. I shortened it to eliminate irrelevant information:

Each line represents a connection in a specific state. In this example, you can see connections in listening states (see the first line, port 22, my ssh server), established states, waiting states and so on.


Final Thoughts

So there you have it: some of the most used CLI commands! Naturally, each of these commands are capable of much more than what I've covered in this tutorial. I hope I've shed a bit of light on some of these CLI mysteries. Thanks for reading!

Tags:

Comments

Related Articles