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.
A Little Computer History: Training Video for Bell Labs' Holmdel Computing Center - AT&T Archives
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.
csaba@csaba-pc ~/Personal/Programming/NetTuts $
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:
csaba@csaba-pc ~/Personal/Programming/NetTuts $ echo $PS1 \[\033[01;32m\]\u@\h\[\033[01;34m\] \w \$\[\033[00m\]
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 -
\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
Each of these commands are capable of much more than what I covered in this tutorial.
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:
csaba@csaba-pc ~ $ mkdir ~/tmp/NetTuts csaba@csaba-pc ~ $ cd ~/tmp/NetTuts/ csaba@csaba-pc ~/tmp/NetTuts $ mkdir ./AnotherDir csaba@csaba-pc ~/tmp/NetTuts $ mkdir ./SecondDir csaba@csaba-pc ~/tmp/NetTuts $ touch ./SecondDir/aFile csaba@csaba-pc ~/tmp/NetTuts $ touch ./SecondDir/AnotherFile csaba@csaba-pc ~/tmp/NetTuts $ cd ./SecondDir/ csaba@csaba-pc ~/tmp/NetTuts/SecondDir $ pushd ~/tmp/NetTuts ~/tmp/NetTuts ~/tmp/NetTuts/SecondDir csaba@csaba-pc ~/tmp/NetTuts $ ls -al total 16 drwxr-xr-x 4 csaba csaba 4096 Feb 19 21:09 . drwx------ 7 csaba csaba 4096 Feb 19 21:09 .. drwxr-xr-x 2 csaba csaba 4096 Feb 19 21:09 AnotherDir drwxr-xr-x 2 csaba csaba 4096 Feb 19 21:09 SecondDir csaba@csaba-pc ~/tmp/NetTuts $ popd ~/tmp/NetTuts/SecondDir csaba@csaba-pc ~/tmp/NetTuts/SecondDir $ ls -al total 8 drwxr-xr-x 2 csaba csaba 4096 Feb 19 21:09 . drwxr-xr-x 4 csaba csaba 4096 Feb 19 21:09 .. -rw-r--r-- 1 csaba csaba 0 Feb 19 21:09 aFile -rw-r--r-- 1 csaba csaba 0 Feb 19 21:09 AnotherFile csaba@csaba-pc ~/tmp/NetTuts/SecondDir $
A line-by-line explanation:
If you are root, the prompt ends with
#
instead of$
.
- Create a directory called NetTuts under /home/csaba/tmp.
- Change current directory to the newly created directory.
- Create a directory called "AnotherDir" inside the current directory.
- Create a directory called "SecondDir" inside the current directory.
- Create two empty files inside "SecondDir" using the touch command.
- Change current directory to SecondDir.
- Use pushd to change directory to ~/tmp/NetTuts in order to put our current directory on a stack.
- List all files in ~/tmp/NetTuts
- Return to our previous directory by issuing a popd command, which fetches (and removes) the top directory from the stack.
- 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.
csaba@csaba-pc ~/tmp/NetTuts/SecondDir $ mcedit ./aFile
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:
$ someCommand <
But what if you want your command to read from a file? Well you can redirect a file into its stdin, like this:
$ someCommand < /your/file.txt
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:
csaba@csaba-pc ~/tmp/NetTuts/SecondDir $ ls -al total 8 drwxr-xr-x 2 csaba csaba 4096 Feb 19 21:09 . drwxr-xr-x 4 csaba csaba 4096 Feb 19 21:09 .. -rw-r--r-- 1 csaba csaba 0 Feb 19 21:09 aFile -rw-r--r-- 1 csaba csaba 0 Feb 19 21:09 AnotherFile csaba@csaba-pc ~/tmp/NetTuts/SecondDir $
You can send that result to a file with the following command:
csaba@csaba-pc ~/tmp/NetTuts/SecondDir $ ls -al > ./ThirdFile
The contents of ThirdFile is:
total 12 drwxr-xr-x 2 csaba csaba 4096 Feb 24 00:06 . drwxr-xr-x 4 csaba csaba 4096 Feb 19 21:09 .. -rw-r--r-- 1 csaba csaba 12 Feb 19 21:19 aFile -rw-r--r-- 1 csaba csaba 0 Feb 19 21:09 AnotherFile -rw-r--r-- 1 csaba csaba 0 Feb 24 00:06 ThirdFile
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.
csaba@csaba-pc ~/tmp/NetTuts/SecondDir $ cd .. csaba@csaba-pc ~/tmp/NetTuts $ ls -al total 16 drwxr-xr-x 4 csaba csaba 4096 Feb 19 21:09 . drwx------ 7 csaba csaba 4096 Feb 19 21:09 .. drwxr-xr-x 2 csaba csaba 4096 Feb 19 21:09 AnotherDir drwxr-xr-x 2 csaba csaba 4096 Feb 24 00:06 SecondDir csaba@csaba-pc ~/tmp/NetTuts $ ls -al >> ./SecondDir/ThirdFile
And our file's content is:
total 12 drwxr-xr-x 2 csaba csaba 4096 Feb 24 00:06 . drwxr-xr-x 4 csaba csaba 4096 Feb 19 21:09 .. -rw-r--r-- 1 csaba csaba 12 Feb 19 21:19 aFile -rw-r--r-- 1 csaba csaba 0 Feb 19 21:09 AnotherFile -rw-r--r-- 1 csaba csaba 0 Feb 24 00:06 ThirdFile total 16 drwxr-xr-x 4 csaba csaba 4096 Feb 19 21:09 . drwx------ 7 csaba csaba 4096 Feb 19 21:09 .. drwxr-xr-x 2 csaba csaba 4096 Feb 19 21:09 AnotherDir drwxr-xr-x 2 csaba csaba 4096 Feb 24 00:06 SecondDir
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:
csaba@csaba-pc ~/tmp/NetTuts $ ls -al > ./SecondDir/ThirdFile csaba@csaba-pc ~/tmp/NetTuts $ ls -al 1> ./SecondDir/ThirdFile
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:
csaba@csaba-pc ~/tmp/NetTuts $ ls -al 1 > ./SecondDir/ThirdFile csaba@csaba-pc ~/tmp/NetTuts $ ls -al 1 1> ./SecondDir/ThirdFile
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.
csaba@csaba-pc ~/tmp/NetTuts $ ls -al inexistenFilder > ./SecondDir/ThirdFile ls: cannot access inexistenFilder: No such file or directory csaba@csaba-pc ~/tmp/NetTuts $ ls -al inexistenFilder 2> ./SecondDir/ThirdFile
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:
csaba@csaba-pc ~/tmp/NetTuts $ ls -al total 16 drwxr-xr-x 4 csaba csaba 4096 Feb 19 21:09 . drwx------ 7 csaba csaba 4096 Feb 19 21:09 .. drwxr-xr-x 2 csaba csaba 4096 Feb 19 21:09 AnotherDir drwxr-xr-x 2 csaba csaba 4096 Feb 24 00:06 SecondDir csaba@csaba-pc ~/tmp/NetTuts $ ls -al ./SecondDir/ total 16 drwxr-xr-x 2 csaba csaba 4096 Feb 24 00:06 . drwxr-xr-x 4 csaba csaba 4096 Feb 19 21:09 .. -rw-r--r-- 1 csaba csaba 12 Feb 19 21:19 aFile -rw-r--r-- 1 csaba csaba 0 Feb 19 21:09 AnotherFile -rw-r--r-- 1 csaba csaba 61 Feb 24 00:23 ThirdFile csaba@csaba-pc ~/tmp/NetTuts $ find . -name ThirdFile ./SecondDir/ThirdFile
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:
csaba@csaba-pc ~/tmp/NetTuts $ find . -name ?File ./SecondDir/aFile csaba@csaba-pc ~/tmp/NetTuts $ find . -name *File ./SecondDir/aFile ./SecondDir/AnotherFile ./SecondDir/ThirdFile
?
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:
csaba@csaba-pc ~/tmp/NetTuts $ mkdir ThirdDir csaba@csaba-pc ~/tmp/NetTuts $ chmod 000 ThirdDir csaba@csaba-pc ~/tmp/NetTuts $ find . -name *File ./SecondDir/aFile ./SecondDir/AnotherFile ./SecondDir/ThirdFile find: `./ThirdDir': Permission denied
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.
csaba@csaba-pc ~/tmp/NetTuts $ find . -name *File 2> /dev/null ./SecondDir/aFile ./SecondDir/AnotherFile ./SecondDir/ThirdFile
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:
csaba@csaba-pc ~/tmp/NetTuts $ find . -name *File 2> /dev/null 1>./SecondDir/ThirdFile csaba@csaba-pc ~/tmp/NetTuts $
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:
find . -name *File 1>./SecondDir/ThirdFile 2>&1
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.
csaba@csaba-pc ~/tmp/NetTuts $ ls -al total 20 drwxr-xr-x 5 csaba csaba 4096 Feb 24 00:44 . drwx------ 7 csaba csaba 4096 Feb 19 21:09 .. drwxr-xr-x 2 csaba csaba 4096 Feb 19 21:09 AnotherDir drwxr-xr-x 2 csaba csaba 4096 Feb 24 00:06 SecondDir d--------- 2 csaba csaba 4096 Feb 24 00:44 ThirdDir
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:
csaba@csaba-pc ~/tmp/NetTuts $ chown csaba:users ./AnotherDir/ csaba@csaba-pc ~/tmp/NetTuts $ ls -al total 20 drwxr-xr-x 5 csaba csaba 4096 Feb 24 00:44 . drwx------ 7 csaba csaba 4096 Feb 19 21:09 .. drwxr-xr-x 2 csaba users 4096 Feb 19 21:09 AnotherDir drwxr-xr-x 2 csaba csaba 4096 Feb 24 00:06 SecondDir d--------- 2 csaba csaba 4096 Feb 24 00:44 ThirdDir
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.
chown: changing ownership of ‘./AnotherDir/’: Operation not permitted csaba@csaba-pc ~/tmp/NetTuts $ ls -al ./ThirdDir/* ls: cannot access ./ThirdDir/*: Permission denied
But its owner does have the rights to change its permissions:
csaba@csaba-pc ~/tmp/NetTuts $ chmod +rwx ./ThirdDir/ csaba@csaba-pc ~/tmp/NetTuts $ ls -al ./ThirdDir total 8 drwxr-xr-x 2 csaba csaba 4096 Feb 24 00:44 . drwxr-xr-x 5 csaba csaba 4096 Feb 24 00:44 .. csaba@csaba-pc ~/tmp/NetTuts $ ls -al total 20 drwxr-xr-x 5 csaba csaba 4096 Feb 24 00:44 . drwx------ 7 csaba csaba 4096 Feb 19 21:09 .. drwxr-xr-x 2 csaba users 4096 Feb 19 21:09 AnotherDir drwxr-xr-x 2 csaba csaba 4096 Feb 24 00:06 SecondDir drwxr-xr-x 2 csaba csaba 4096 Feb 24 00:44 ThirdDir
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.
csaba@csaba-pc ~/tmp/NetTuts $ chmod +r-w ./ThirdDir/ csaba@csaba-pc ~/tmp/NetTuts $ ls -al total 20 drwxr-xr-x 5 csaba csaba 4096 Feb 24 00:44 . drwx------ 7 csaba csaba 4096 Feb 19 21:09 .. drwxr-xr-x 2 csaba users 4096 Feb 19 21:09 AnotherDir drwxr-xr-x 2 csaba csaba 4096 Feb 24 00:06 SecondDir dr-xr-xr-x 2 csaba csaba 4096 Feb 24 00:44 ThirdDir
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.
csaba@csaba-pc ~/tmp/NetTuts $ chmod 765 ./ThirdDir/ csaba@csaba-pc ~/tmp/NetTuts $ ls -al total 20 drwxr-xr-x 5 csaba csaba 4096 Feb 24 00:44 . drwx------ 7 csaba csaba 4096 Feb 19 21:09 .. drwxr-xr-x 2 csaba users 4096 Feb 19 21:09 AnotherDir drwxr-xr-x 2 csaba csaba 4096 Feb 24 00:06 SecondDir drwxrw-r-x 2 csaba csaba 4096 Feb 24 00:44 ThirdDir
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.
csaba@csaba-pc ~/tmp/NetTuts $ cat ./SecondDir/ThirdFile ./SecondDir/aFile ./SecondDir/AnotherFile ./SecondDir/ThirdFile find: `./ThirdDir': Permission denied
Grep
Grep searches for a pattern and outputs the matching lines. You can optionally specify a file to search as the third parameter:
csaba@csaba-pc ~/tmp/NetTuts $ grep "AnotherFile" ./SecondDir/ThirdFile ./SecondDir/AnotherFile
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:
csaba@csaba-pc ~/tmp/NetTuts $ cat ./SecondDir/ThirdFile | grep "Another" ./SecondDir/AnotherFile
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.
csaba@csaba-pc ~/tmp/NetTuts $ cat ./SecondDir/ThirdFile | grep "Another" | sed -e "s/AnotherFile/MyFile/" ./SecondDir/MyFile
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:
csaba@csaba-pc ~/tmp/NetTuts $ ssh [email protected] -p 8743
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'
.
csaba@csaba-pc ~/tmp/NetTuts $ alias sshcon='ssh [email protected] -p 8743'
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.
csaba@csaba-pc ~/tmp/NetTuts $ mcedit ~/.bashrc
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.
csaba@csaba-pc ~/tmp/NetTuts $ ping 8.8.8.8 PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data. 64 bytes from 8.8.8.8: icmp_seq=1 ttl=47 time=44.0 ms 64 bytes from 8.8.8.8: icmp_seq=2 ttl=47 time=65.6 ms ^C --- 8.8.8.8 ping statistics --- 2 packets transmitted, 2 received, 0% packet loss, time 1000ms rtt min/avg/max/mdev = 44.081/54.871/65.661/10.790 ms csaba@csaba-pc ~/tmp/NetTuts $ ping inexistent.server ping: unknown host inexistent.server
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.
csaba@csaba-pc ~/tmp/NetTuts $ traceroute 8.8.8.8 traceroute to 8.8.8.8 (8.8.8.8), 30 hops max, 60 byte packets 1 192.168.111.1 (192.168.111.1) 0.239 ms 0.322 ms 0.317 ms 2 * * * 3 95.77.39.65 (95.77.39.65) 45.754 ms 45.887 ms 46.024 ms 4 ro-cj01a-rd4-xe-1-2-1-v1643.upcnet.ro (84.116.216.1) 83.121 ms ro-cj01a-rd4-xe-1-2-0-v1642.upcnet.ro (84.116.225.253) 83.289 ms ro-cj01a-rd4-xe-1-3-0-v1713.upcnet.ro (84.116.217.26) 83.119 ms 5 84.116.217.93 (84.116.217.93) 83.153 ms 84.116.217.85 (84.116.217.85) 77.407 ms 77.350 ms 6 84-116-131-53.aorta.net (84.116.131.53) 77.327 ms 53.442 ms 53.357 ms 7 84.116.132.174 (84.116.132.174) 53.211 ms 48.923 ms 53.186 ms 8 72.14.219.9 (72.14.219.9) 85.040 ms 72.14.214.29 (72.14.214.29) 67.289 ms 72.216 ms 9 209.85.241.110 (209.85.241.110) 48.129 ms 47.389 ms 209.85.240.64 (209.85.240.64) 45.096 ms 10 72.14.239.62 (72.14.239.62) 47.254 ms 72.14.236.68 (72.14.236.68) 51.770 ms 72.14.239.62 (72.14.239.62) 43.242 ms 11 209.85.254.118 (209.85.254.118) 46.137 ms 209.85.254.116 (209.85.254.116) 52.165 ms 209.85.254.114 (209.85.254.114) 102.070 ms 12 * * * 13 google-public-dns-a.google.com (8.8.8.8) 47.471 ms 47.986 ms 43.645 ms
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.
csaba@csaba-pc ~/tmp/NetTuts $ route Kernel IP routing table Destination Gateway Genmask Flags Metric Ref Use Iface default 192.168.111.1 0.0.0.0 UG 0 0 0 eno1 loopback localhost 255.0.0.0 UG 0 0 0 lo 192.168.111.0 * 255.255.255.0 U 1 0 0 eno1
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.
csaba@csaba-pc ~/tmp/NetTuts $ ifconfig eno1: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500 inet 192.168.111.10 netmask 255.255.255.0 broadcast 192.168.111.255 inet6 fe80::4e72:b9ff:fef6:c9ff prefixlen 64 scopeid 0x20<link> ether 4c:72:b9:f6:c9:ff txqueuelen 1000 (Ethernet) RX packets 2935016 bytes 696255521 (664.0 MiB) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 5586410 bytes 6331639146 (5.8 GiB) TX errors 0 dropped 0 overruns 0 carrier 1 collisions 0 device interrupt 17 lo: flags=73<UP,LOOPBACK,RUNNING> mtu 16436 inet 127.0.0.1 netmask 255.0.0.0 inet6 ::1 prefixlen 128 scopeid 0x10<host> loop txqueuelen 0 (Local Loopback) RX packets 7396 bytes 599533 (585.4 KiB) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 7396 bytes 599533 (585.4 KiB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
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:
csaba@csaba-pc ~/tmp/NetTuts $ netstat -an Active Internet connections (servers and established) Proto Recv-Q Send-Q Local Address Foreign Address State tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN tcp 0 0 127.0.0.1:631 0.0.0.0:* LISTEN tcp 0 0 0.0.0.0:59017 0.0.0.0:* LISTEN tcp 0 40 192.168.111.10:59017 109.99.97.81:53681 ESTABLISHED tcp 0 0 192.168.111.10:51137 109.99.97.81:55175 TIME_WAIT tcp 0 0 192.168.111.10:34715 173.194.70.109:993 ESTABLISHED tcp 0 0 192.168.111.10:34722 173.194.70.109:993 ESTABLISHED tcp 0 1 192.168.111.10:42876 86.162.58.4:7055 LAST_ACK tcp6 0 0 :::111 :::* LISTEN tcp6 0 0 :::4434 :::* LISTEN tcp6 0 0 :::59017 :::* LISTEN
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!
Comments