LINUX SHELL
SSH... http://ssh.com/index.php/resource-overview/brochures.html
From...http://en.wikipedia.org/wiki/Linux
Linux (i/ˈlɪnəks/ lin-əks[5][6] or /ˈlɪnʊks/ lin-uuks)[7][8][9] is a Unix-like computer operating system assembled under the model of free and open source software development and
distribution. The defining component of any Linux system is the Linux kernel, an operating system kernel first released October 5, 1991 by Linus Torvalds.[10][11] Linux system distributions may vary in many details of system operation, configuration, and software package selections.
Linux runs on a wide variety of computer hardware, including mobile phones, tablet computers, network routers, televisions[12][13], video game consoles, desktop computers, mainframes and supercomputers.[14][15][16][17] Linux is a leading server operating system, and runs the 10 fastest supercomputers in the world.[18] In addition, more than 90% of today's supercomputers run some variant of Linux.[19]
The development of Linux is one of the most prominent examples of free and open source software collaboration: the underlying source code may be used, modified, and distributed—commercially or non-commercially—by anyone under licenses such as the GNU General Public License. Typically Linux is packaged in a format known as a Linux distribution for desktop and server use. Some popular mainstream Linux distributions include Debian (and its derivatives such as Ubuntu), Fedora and openSUSE. Linux distributions include the Linux kernel, supporting utilities and libraries and usually a large amount of application software to fulfill the distribution's intended use.
A distribution oriented toward desktop use may include the X Window System and an accompanying desktop environment such as GNOME or KDE Plasma. Other distributions may include a less resource intensive desktop such as LXDE or Xfce for use on older or less-powerful computers. A distribution intended to run as a server may omit any graphical environment from the standard install and instead include other software such as the Apache HTTP Server and a SSH server like OpenSSH. Because Linux is freely redistributable, it is possible for anyone to create a distribution for any intended use. Commonly used applications with desktop Linux systems include the Mozilla Firefox web browser, the OpenOffice.org or LibreOffice office application suites, and the GIMP image editor.
The main supporting user space system tools and libraries from the GNU Project (announced in 1983 by Richard Stallman) are the basis for the Free Software Foundation's preferred name GNU/Linux.[20][21]
from... http://www.arachnoid.com/linux/shell_programming.html
Bash what?
Okay, I grant that this page might represent a leap from the familiar to the alien without much warning. Here are some explananatory notes:
- Under Linux, there are some powerful tools that for all practical purposes are unavailable under Windows (I can imagine all the old Linux hands saying "Duh!").
- One of these tools is something called "shell programming". This means writing code that a command shell executes.
- There is something like this under Windows, but as usual, the Windows version is a weak imitation.
- The most common Linux shell is named "Bash". The name comes from "Bourne Again SHell," which, in turn ... (imagine a lengthy recursion terminating in a caveman's grunt).
- There are many other shells available. Unless there is a compelling reason not to, I recommend that people stick to the Bash shell, because this increases the chance that your scripts will be portable between machines, distributions, even operating systems.
- I'll be showing some very basic examples of Bash shell programming on this page, and I want to say at the outset that shell programming is an art, not a science. That means there is always some other way to do the same thing.
- Because shell programming is an art, please don't write to say, "Wow, that was a really inefficient way to do such-and-such." Please do write (message page) to report actual errors.
- If this page seems too sketchy and elementary for your taste, you can choose from among the more advanced resources in this list.
Introduction
-
Early computers had a teletype machine with a keyboard for I/O. Later, glass terminals became the norm, but the behavior was much the same — a keyboard, a screen, a text display. A program was responsible for mediating the transaction between the operator and the machine, and as the years passed this program (the command interpreter or shell) became more sophisticated.
-
At this stage the command shell has become rather too sophisticated, typically having a dozen ways to do any particular thing. In this page I will try to limit myself to describing a handful of useful operations, based not on listing everything that can be done, but on solving specific problems. There are some links at the bottom of this page for those wanting more depth.
Preliminaries
-
There are two primary ways to use the shell: interactively and by writing shell scripts.
- In the interactive mode, the user types a single command (or a short string of commands) and the result is printed out.
- In shell scripting, the user types anything from a few lines to an entire program into a text editor, then executes the resulting text file as a shell script.
- It is often the case that an interactive session becomes a shell scripting session, once things get too complicated for simple interactive line entries, or because a specific sequence of commands appears to be generally useful and worth preserving.
- In a modern Linux environment the user can have more than one shell open at a time, either by moving between a sequence of independent "virtual terminals" in a text-only environment, or by opening any number of shell windows in the X Windows environment.
- The advantage of having more than one shell available is that one shell can be used for testing one command at a time, while another might provide a text editor for assembling single commands into a shell program.
- I don't want to get too distribution-specific, but if you are not hosting X Windows and want more than one simultaneous shell session, with many current distributions you can switch between "virtual terminals" by pressing Ctrl+Alt+F(n), n typically between 1 and 6.
- In an environment that supports X Windows, simply open any desired number of command shell windows and move between them.
Simple Stuff
-
First, a convention. I'll list things for you to type in this format:
$ date
I will list the computer's reply like this:
Tue Dec 23 10:52:51 PST 2003
Notice the "$" symbol in the user entry above. This is a generic shell prompt, and yours will almost certainly look different (but it will include a similar symbol). I'll be using one of two prompts (this is a common convention, worth remembering): I'll use "$" to refer to a normal user session, and "#" to refer to a root session. -
NOTE: Avoid using root sessions and permissions unless it is required. Misused root authority can cause very serious harm to your system. Since this is a tutorial in which you will want to experiment with different commands, limit the chance for harm by doing so as an ordinary user.
-
To put this another way, enter this example:
# whoami
root
If your session produced the result shown above, please — log out and become an ordinary user.
-
In shell programming, spaces matter. If you see spaces between words and characters in these examples, be sure to include the spaces.
-
In shell programming, case matters also. If you don't get the results shown on this page, look at the case of your entries.
Where are you?
-
As you may be aware, a Linux filesystem is in the form of a large tree with many branches called "subdirectories". When you issue a shell command, it is often necessary to know where you are in the "tree". Type this example:
$ pwd
/path/path/path
When you try this example ("pwd" means "print working directory"), your current working directory will be printed.
-
You can decide where you are in the tree. Type this example:
$ cd ~
$ pwd
/home/username
The symbol "~" is a special shortcut character that can be used to refer to your home directory. You could have typed this —
$ cd /home/username
— and accomplished the same result, but if you think about it, the "~" character is more portable. Later, when you are writing shell scripts, you might want a command that moves to any user's home directory.
Listing Files
-
Directories contain files, and you can list them in a simple, compact format:
$ ls
filename filename filename ...
Or you can list them in more detail:
$ ls -la
(detailed list, one file per line)
And, very important, to find out what a command's options are, use the "man" (manual) command:
$ man ls
(manual page for "ls")
NOTE: The "man" command allows you to learn a command's options. You still have to remember the command's name.
To find files by name:
$ find . -name '*.jpg'
(list of files with .jpg suffix in current and all child directories)
To create a text diagram of the directory tree:
$ tree -d .
(diagram of the directory tree from the current directory)
The "tree" command is less useful now that directory trees have become so complicated, and now that most distributions support X Windows and sophisticated filesystem browsers.
Examining Files
-
There are a number of things you can do to find out more about the files in the list. Here are just a few:
The "file" command tries to identify files by examining their contents:
$ file tux_small.png
tux_small.png: PNG image data, 128 x 151, 8-bit/color RGB, non-interlaced
The next example uses the obscurely named "cat" command. It prints the contents of a file. Unfortunately if the file's contents are not readable, they get printed anyway.
$ cat zipcodes.txt
(prints the entire contents of a file named "zipcodes.txt")
If a file is too long to be viewed on one page, you can say:
$ more zipcodes.txt
(prints file one screenful at a time)
You can also use "grep" to print only those parts of a file you are interested in:
$ grep 10001 zipcodes.txt
(prints only those lines that have the character string "10001" in them)
The "grep" command is very useful, unfortunately it has a difficult-to-remember name. Be sure to:
$ man grep
There are many, many more shell commands to learn and to use. You may want to browse the list of Useful Links for more detail.
Pipelines and Redirection
-
You can use a pipeline (symbolized by "|") to make the output of one command serve as the input to another command. This idea can be used to create a combination of commands to accomplish something no single command can do.
Enter this command:
$ echo "cherry apple peach"
cherry apple peach
Okay, let's say we want to sort these words alphabetically. There is a command "sort", but it sorts entire lines, not words, so we need to break this single line into individual lines, one line per word.
Step one: pipe the output of "echo" into a translation (tr) command that will replace spaces with linefeeds (represented by "\n"):
$ echo "cherry apple peach" | tr " " "\n"
cherry
apple
peach
Success: each word appears on a separate line. Now we are ready to sort.
Step two: add the sort command:
$ echo "cherry apple peach" | tr " " "\n" | sort
apple
cherry
peach
Let's try reversing the order of the sort:
$ echo "cherry apple peach" | tr " " "\n" | sort -r
peach
cherry
apple
-
Remember: A pipeline ("|") takes the output of one command and makes it the input to another command.
-
Normally the output from commands is printed on the screen. But using the symbol ">", you can redirect the output to a file:
$ date > RightNow.txt
$ cat RightNow.txt
Tue Dec 23 14:43:33 PST 2003
The above example used ">" to replace the content of any existing file having the name "RightNow.txt". To append new data to an existing file, use ">>" instead:
$ date >> RightNow.txt
$ cat RightNow.txt
Tue Dec 23 14:43:33 PST 2003
Tue Dec 23 14:46:10 PST 2003
-
Remember: Use ">" to overwrite any existing file, use ">>" to append to any existing file. In both cases, if no file exists, one is created.
- Many commands have inputs as well as outputs. The input defaults to the keyboard, the output defaults to the screen.
- To redirect the output to a file, use ">" or ">>" as shown above.
- To make the output of a command serve as the input of another command, use "|".
-
To make the contents of a file serve as the input to a command, use "<":
$ wc < RightNow.txt
2 12 58
As is so often the case in shell programming, there is at least one other way to produce the above result:
$ cat RightNow.txt | wc
2 12 58
Shell Script Basics
-
A shell script is a plain-text file that contains shell commands. It can be executed by typing its name into a shell, or by placing its name in another shell script.
-
To be executable, a shell script file must meet some conditions:
-
The file must have a special first line that names an appropriate command processor. For this tutorial, the following will work in most cases:
#!/bin/bash
If this example doesn't work, you will need to find out where your Bash shell executable is located and substitute that location in the above example. Here is one way to find out:
$ whereis bash
-
The file must be made executable by changing its permission bits. An example:
$ chmod +x (shell script filename)
-
The file must have a special first line that names an appropriate command processor. For this tutorial, the following will work in most cases:
-
A shell script file may optionally have an identifying suffix, like ".sh". This only helps the user remember which files are which. The command processor responsible for executing the file uses the executable bit, plus the file's first line, to decide how to handle a shell script file.
-
One normally executes a shell script this way:
$ ./scriptname.sh
This special entry is a way to tell the command processor that the desired script is located in the current directory. Always remember: if you cannot get your shell script to run, remember this trick to provide its location as well as its name.
First Shell Script
-
This will get you past the details of writing and launching a simple script.
-
Choose a text editor you want to use. It can be a command-line editor like emacs, pico or vi, or an X Windows editor if you have this option.
-
Run your choice of editor and type the following lines:
#!/bin/bash
echo "Hello, world."
NOTE: Be sure to place a linefeed at the end of your script. Forgetting a terminating linefeed is a common beginner's error. -
Save the file in the current working directory as "myscript.sh".
-
Move from the text editor to a command shell.
-
From the command shell, type this:
$ chmod +x myscript.sh
-
To execute the script, type this:
$ ./myscript.sh
Hello, world.
-
Choose a text editor you want to use. It can be a command-line editor like emacs, pico or vi, or an X Windows editor if you have this option.
- These steps will become second nature soon enough.
Tests and Branching
-
Bash shell scripts can perform, and act on, various kinds of tests. This will be just the most basic introduction — see the reference material at Useful Links for more on this rather baroque topic.
-
To follow these and other examples that involve multiline shell scripts, please set up to edit and run a test script file (let's call it "myscript.sh") that you can use to enter and test various options. And remember that the examples won't include the all-important first line of the script (see script examples above) — it will be assumed to exist in each case.
Also, to save time, you may want to copy some of the shell code examples from this page directly into your editor.
-
Here is an example of a test and branch:
if [ -e . ]
then
echo "Yes."
else
echo "No."
fi
Run the test script:
$ ./myscript.sh
Yes.
We created a test (the part of the script between "[" and "]") which tested whether a particular element existed ("-e"). Because the symbol "." in this context means the current directory, the test succeeded. Try replacing the "." with something that is not present in the current directory, example "xyz". See how the outcome changes.
It is important to realize that "[" is an alias for the command "test". The script could have been written as:
if test -e .
then
echo "Yes."
else
echo "No."
fi
NOTE: Be sure to read the "test" man page to find out all the different tests that are available:
$ man test
Before we move on, there is a perversity about tests in Bash shells that I want to discuss. It turns out, because of a historical accident that now might as well be cast in concrete, when a test is conducted or a command returns a result value, the numerical value for "true" is 0, and "false" is 1. Those of you who have some programming experience will likely find this reversal of intuition as annoying as I do.
Here is a way to get the result of the most recent logical test (and to show the weird reversal described above):
$ test -e .
$ echo $?
0
$ test -e xyz
$ echo $?
1
Please remember this reversal, because it confounds the process of thinking through, and constructing, logical tests. For example, you may want to write a shortcut form for a test that only acts on one kind of result:
$ test -e . && echo "Yes."
Yes.
This sort of shorthand relies on some knowledge of logical processing — if the left-hand part of an AND test yields "true", then the right-hand part must also be evaluated, and so it is. But the numerical "true" value for the left-hand test is 0, which would argue for the opposite logic.
Just to show how perverse this all is, here is an example of Bash logical testing that comes out the opposite way:
$ echo $(( 0 && 0 ))
0
$ echo $(( 1 && 0 ))
0
$ echo $(( 0 && 1 ))
0
$ echo $(( 1 && 1 ))
1
Yes, just as you would expect. So do be on guard against this shell "gotcha", which only affects the outcome of tests and command result values. It probably will not surprise you to learn that no one mentions this strange anomaly in the official Bash documentation.
A couple of rules about logical operators used as branches:- If you write "test && command", the command will only be executed if the test succeeds.
-
If you write "test || command", the command will only be executed if the test fails.
Run these tests:
$ true && echo "Yes."
Yes.
$ false || echo "Yes."
Yes.
Notice that the outcomes are entirely in keeping with one's intuition about such logical comparisons, and all is well as long as you don't think about the fact that true equals 0. :)
Here's another scheme commonly seen in shell script programming and interactive sessions:
$ command1 && command2 && command3 && command4
This line of code will not run the next command in the sequence unless the prior command has returned "true", meaning no errors. It is a way to avoid running a command if a required prior outcome is not present.
Loops and Repetition
-
Here are some examples of loop operators:
for fn in *; do
echo "$fn"
done
In this example, the "*" is expanded by the shell to a list of all the files in the current directory, then each filename is applied to the loop control area. In such a construct, any whitespace-delimited list will do:
for fn in tom dick harry; do
echo "$fn"
done
$ ./myscript.sh
tom
dick
harry
This method will work for any list that uses spaces as delimiters. But what happens if you must parse a list that must be delimited by linefeeds instead of spaces, such as the case of a list of filenames or paths that contain spaces as part of their names?
You can solve such a problem this way (there are other solutions):
ls -1 | while read fn; do
echo "$fn"
done
This example uses an option to "ls" (note: the option is "-" followed by the numerical digit "1", not a lowercase "L") that formats file listings with one name per line, then this list is pipelined to a routine that reads lines until there are no more to read. This meets the requirement that linefeeds become the delimiters between list elements, not spaces.
There is plenty more to this topic. Please refer to the list of Useful Links for more.
Using Numbers in Scripts
-
Contrary to a sometimes-expressed view, numbers can easily be accommodated in scripts. Example:
n=1
while [ $n -le 6 ]; do
echo $n
let n++
done
$ ./myscript.sh
1
2
3
4
5
6
Notice the "let" command, which treats its argument in a way meant to accommodate numbers.
Here is a somewhat more complex example:
y=1
while [ $y -le 12 ]; do
x=1
while [ $x -le 12 ]; do
printf "% 4d" $(( $x * $y ))
let x++
done
echo ""
let y++
done
$ ./myscript.sh
1 2 3 4 5 6 7 8 9 10 11 12
2 4 6 8 10 12 14 16 18 20 22 24
3 6 9 12 15 18 21 24 27 30 33 36
4 8 12 16 20 24 28 32 36 40 44 48
5 10 15 20 25 30 35 40 45 50 55 60
6 12 18 24 30 36 42 48 54 60 66 72
7 14 21 28 35 42 49 56 63 70 77 84
8 16 24 32 40 48 56 64 72 80 88 96
9 18 27 36 45 54 63 72 81 90 99 108
10 20 30 40 50 60 70 80 90 100 110 120
11 22 33 44 55 66 77 88 99 110 121 132
12 24 36 48 60 72 84 96 108 120 132 144
Coping with user input
-
Here is an example that relies on user input to decide what to do. It exploits a shell feature as an easy way to create a menu of choices:
PS3="Choose (1-5):"
echo "Choose from the list below."
select name in red green blue yellow magenta
do
break
done
echo "You chose $name."
When run, it looks like this:
$ ./myscript.sh
Choose from the list below.
1) red
2) green
3) blue
4) yellow
5) magenta
Choose (1-5):4
You chose yellow.
As written, this menu code won't catch some kinds of errors (like a number that is out of range). In any application where the user choice must fall into defined bounds, be sure to perform a test on the result before using it. Example:
if [ "$name" = "" ]; then
echo "Error in entry."
exit 1
fi
An advanced example with numbers and user input
-
Here is an example guessing game that ties together some of the elements we've covered so far:
secretNumber=$(( ((`date +%N` / 1000) % 100) +1 ))
guess=-1
while [ "$guess" != "$secretNumber" ]; do
echo -n "I am thinking of a number between 1 and 100. Enter your guess:"
read guess
if [ "$guess" = "" ]; then
echo "Please enter a number."
elif [ "$guess" = "$secretNumber" ]; then
echo -e "\aYes! $guess is the correct answer!"
elif [ "$secretNumber" -gt "$guess" ]; then
echo "The secret number is larger than your guess. Try again."
else
echo "The secret number is smaller than your guess. Try again."
fi
done
Please study this example carefully, and refer to the reference materials in Useful Links to understand some of the methods.
Creating and using arrays
-
Shell arrays are relatively easy to construct. Example:
array=(red green blue yellow magenta)
len=${#array[*]}
echo "The array has $len members. They are:"
i=0
while [ $i -lt $len ]; do
echo "$i: ${array[$i]}"
let i++
done
Run this example:
$ ./myscript.sh
The array has 5 members. They are:
0: red
1: green
2: blue
3: yellow
4: magenta
Now, before you decide this is a silly, rather useless example, replace one line of the script and run it again:
array=(`ls`)
See what difference this makes (and think of all the kinds of lists you might create for this line).
Strings and substrings
-
It's useful to be able to take strings apart and put them together in different ways. Here is how to select a substring from a string:
string="this is a substring test"
substring=${string:10:9}
In this example, the variable "substring" contains the word "substring". Remember this rule:
substring=${string_variable_name:starting_position:length}
The string starting position is zero-based.
Searching and Replacing Substrings within Strings
-
In this method you can replace one or more instances of a string with another string. Here is the basic syntax:
alpha="This is a test string in which the word \"test\" is replaced."
beta="${alpha/test/replace}"
The string "beta" now contains an edited version of the original string in which the first case of the word "test" has been replaced by "replace". To replace all cases, not just the first, use this syntax:
beta="${alpha//test/replace}"
Note the double "//" symbol.
Here is an example in which we replace one string with another in a multi-line block of text:
list="cricket frog cat dog"
poem="I wanna be a x\n\
A x is what I'd love to be\n\
If I became a x\n\
How happy I would be.\n"
for critter in $list; do
echo -e ${poem//x/$critter}
done
Run this example:
$ ./myscript.sh
I wanna be a cricket
A cricket is what I'd love to be
If I became a cricket
How happy I would be.
I wanna be a frog
A frog is what I'd love to be
If I became a frog
How happy I would be.
I wanna be a cat
A cat is what I'd love to be
If I became a cat
How happy I would be.
I wanna be a dog
A dog is what I'd love to be
If I became a dog
How happy I would be.
Silly example, huh? It should be obvious that this search & replace capability could have many more useful purposes.
More obscure but useful string operations
-
Here is a way to isolate something useful from a large, even multi-line, string. As above, this method relies on enclosing a variable name in curly braces, then aplying a special operator to achieve a particular result.
Here is a list of four such operators:-
Operator "#" means "delete from the left, to the first case of what follows."
$ x="This is my test string."
$ echo ${x#* }
is my test string.
-
Operator "##" means "delete from the left, to the last case of what follows."
$ x="This is my test string."
$ echo ${x##* }
string.
-
Operator "%" means "delete from the right, to the first case of what follows."
$ x="This is my test string."
$ echo ${x% *}
This is my test
-
Operator "%%" means "delete from the right, to the last case of what follows."
$ x="This is my test string."
$ echo ${x%% *}
This
I find these operators particularly useful in parsing multi-line strings. Let's say I want to isolate a particular IP address from the output of the "ifconfig" command. Here's how I would proceed:
$ x=`/sbin/ifconfig`
$ echo $x
eth0 Link encap:Ethernet HWaddr 00:0D:56:0C:8D:10
inet addr:192.168.0.1 Bcast:192.168.0.255 Mask:255.255.255.0
inet6 addr: fe80::20d:56ff:fe0c:8d10/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:253339 errors:0 dropped:0 overruns:0 frame:0
TX packets:423729 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:36150085 (34.4 MiB) TX bytes:496768499 (473.7 MiB)
Base address:0xecc0 Memory:fe4e0000-fe500000
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
inet6 addr: ::1/128 Scope:Host
UP LOOPBACK RUNNING MTU:16436 Metric:1
RX packets:109394 errors:0 dropped:0 overruns:0 frame:0
TX packets:109394 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:12372380 (11.7 MiB) TX bytes:12372380 (11.7 MiB)
There's lots of information, more than we need. Let's say for the sake of argument that I want the IP of "lo", the loopback interface. I could specify this:
$ y=${x#*inet addr:}
But, while gobbling text from the left, this search would stop at the IP address of eth0, not the desired interface. So I can specify it this way:
$ y=${x#*lo *inet addr:}
As a last step I'll trim off all remaining text to the right:
$ y=${y%% *}
Leaving only the desired address.
It seems the "#" and "%" operators, and their variants, are able to accept a rather complex argument and sort through the content of large strings, including strings with line breaks. This means I can use the shell to directly filter content in some simple cases where I might have considered using sed or Perl.
-
Operator "#" means "delete from the left, to the first case of what follows."
Bash Version 3
I have always thought the inability to test for the presence of a string or pattern (without using grep, sed or something similar) was a conspicuous weakness in shell programming. Bash version 3, present on must current Linux distributions, addresses this lack by allowing regular expression matching.
Let's say we need to establish whether variable $x appears to be a social security number:
if [[ $x =~ [0-9]{3}-[0-9]{2}-[0-9]{4} ]]
then
# process SSN
else
# print error message
fi
Notice the Perlish "=~" syntax and that the regular expression appears within double brackets. A substantial number of regular expression metacharacters are supported, but not some of the Perl-specific extensions like \w, \d and \s.
Another Bash 3 feature is an improved brace expansion operator:
$ echo {a..z}
a b c d e f g h i j k l m n o p q r s t u v w x y z
for n in {0..5}
do
echo $n
done
0
1
2
3
4
5
Useful Links
Well, as long-winded as it turned out to be, this page is supposed to be an introduction to shell programming, one that just touches the highlights. The linked references below will provide a deeper understanding of the covered topics.
- Log in to post comments
Comments
adminatl
Mon, 01/02/2012 - 13:03
Permalink
SSH TUTORIAL FOR LINUX
This document covers the SSH client on the Linux Operating System and other OSes that use OpenSSH. If you use Windows, please read the document SSH Tutorial for Windows If you use Mac OS X or other Unix based system, you should already have OpenSSH installed and can use this document as a reference.
This article is one of the top tutorials covering SSH on the Internet. It was originally written back in 1999 and was completely revised in 2006 to include new and more accurate information. As of October, 2008, it has been read by over 473,600 people and consistently appears at the top of Google's search results for SSH Tutorial and Linux SSH.
Contents
[hide]
What Is SSH?
There are a couple of ways that you can access a shell (command line) remotely on most Linux/Unix systems. One of the older ways is to use the telnet program, which is available on most network capable operating systems. Accessing a shell account through the telnet method though poses a danger in that everything that you send or receive over that telnet session is visible in plain text on your local network, and the local network of the machine you are connecting to. So anyone who can "sniff" the connection in-between can see your username, password, email that you read, and commands that you run. For these reasons you need a more sophisticated program than telnet to connect to a remote host.
An unencrypted telnet session
SSH, which is an acronym for Secure SHell, was designed and created to provide the best security when accessing another computer remotely. Not only does it encrypt the session, it also provides better authentication facilities, as well as features like secure file transfer, X session forwarding, port forwarding and more so that you can increase the security of other protocols. It can use different forms of encryption ranging anywhere from 512 bit on up to as high as 32768 bits and includes ciphers like AES (Advanced Encryption Scheme), Triple DES, Blowfish, CAST128 or Arcfour. Of course, the higher the bits, the longer it will take to generate and use keys as well as the longer it will take to pass data over the connection.
An encrypted ssh session
These two diagrams on the left show how a telnet session can be viewed by anyone on the network by using a sniffing program like Ethereal (now called Wireshark) or tcpdump. It is really rather trivial to do this and so anyone on the network can steal your passwords and other information. The first diagram shows user jsmith logging in to a remote server through a telnet connection. He types his username jsmith and password C0lts06!, which are viewable by anyone who is using the same networks that he is using.
The second diagram shows how the data in an encrypted connection like SSH is encrypted on the network and so cannot be read by anyone who doesn't have the session-negotiated keys, which is just a fancy way of saying the data is scrambled. The server still can read the information, but only after negotiating the encrypted session with the client.
When I say scrambled, I don't mean like the old cable pay channels where you can still kinda see things and hear the sound, I mean really scrambled. Usually encryption means that the data has been changed to such a degree that unless you have the key, its really hard to crack the code with a computer. It will take on the order of years for commonly available computer hardware to crack the encrypted data. The premise being that by the time you could crack it, the data is worthless.
Getting Started
This tutorial isn't going to cover how to install SSH, but will cover how to use it for a variety of tasks. Consult your Linux distribution's document for information on how to setup OpenSSH.
Chances are that if you are using a version of Linux that was released after 2002, that you already have OpenSSH installed. The version of SSH that you will want to use on Linux is called OpenSSH. As of this writing (October 2009), the latest version available is 5.3, but you may encounter versions from 3.6 on up. If you are using anything lower than version 3.9, I'd strongly advise you to upgrade it.
OpenSSH can be obtained from http://www.openssh.org/
To really make ssh useful, you need a shell account on a remote machine, such as on a suso.org account.
The first thing we'll do is simply connect to a remote machine. This is accomplished by running 'ssh hostname' on your local machine. The hostname that you supply as an argument is the hostname of the remote machine that you want to connect to. By default ssh will assume that you want to authenticate as the same user you use on your local machine. To override this and use a different user, simply use remoteusername@hostname as the argument. Such as in this example:
ssh username@username.suso.org
The first time around it will ask you if you wish to add the remote host to a list of known_hosts, go ahead and say yes.
The authenticity of host 'arvo.suso.org (216.9.132.134)' can't be established. RSA key fingerprint is 53:b4:ad:c8:51:17:99:4b:c9:08:ac:c1:b6:05:71:9b. Are you sure you want to continue connecting (yes/no)? yes Warning: Permanently added 'arvo.suso.org' (RSA) to the list of known hosts.
It is important to pay attention to this question however because this is one of SSH's major features. Host validation. To put it simply, ssh will check to make sure that you are connecting to the host that you think you are connecting to. That way if someone tries to trick you into logging into their machine instead so that they can sniff your SSH session, you will have some warning, like this:
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @ WARNING: POSSIBLE DNS SPOOFING DETECTED! @ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ The RSA host key for arvo.suso.org has changed, and the key for the according IP address 216.9.137.122 is unchanged. This could either mean that DNS SPOOFING is happening or the IP address for the host and its host key have changed at the same time. Offending key for IP in /home/suso/.ssh/known_hosts:10 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY! Someone could be eavesdropping on you right now (man-in-the-middle attack)! It is also possible that the RSA host key has just been changed. The fingerprint for the RSA key sent by the remote host is 96:92:62:15:90:ec:40:12:47:08:00:b8:f8:4b:df:5b. Please contact your system administrator. Add correct host key in /home/suso/.ssh/known_hosts to get rid of this message. Offending key in /home/suso/.ssh/known_hosts:53 RSA host key for arvo.suso.org has changed and you have requested strict checking. Host key verification failed.
If you ever get a warning like this, you should stop and determine if there is a reason for the remote server's host key to change (such as if SSH was upgraded or the server itself was upgraded). If there is no good reason for the host key to change, then you should not try to connect to that machine until you have contacted its administrator about the situation. If this is your own machine that you are trying to connect to, you should do some computer forensics to determine if the machine was hacked (yes, Linux can be hacked). Or maybe your home computer's IP address has changed such as if you have a dynamic IP address for DSL. One time I received this message when trying to connect to my home machine's DSL line. I thought it was odd since I hadn't upgraded SSH or anything on my home machine and so I choose not to try to override the cached key. It was a good thing that I didn't try because I found out that my dynamic IP address had changed and that out of chance, another Linux machine running OpenSSH took my old IP.
After saying yes, it will prompt you for your password on the remote system. If the username that you specified exists and you type in the remote password for it correctly then the system should let you in. If it doesn't, try again and if it still fails, you might check with the administrator that you have an account on that machine and that your username and password is correct.
Generating a key
Now that you have spent all that time reading and are now connected, go ahead and logout. ;-) Once you're back to your local computer's command prompt enter the command 'ssh-keygen -t dsa'.
ssh-keygen -t dsa
It should begin spitting out the following:
Generating public/private dsa key pair. Enter file in which to save the key (/home/localuser/.ssh/id_dsa): Enter passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved in /home/localuser/.ssh/id_dsa. Your public key has been saved in /home/localuser/.ssh/id_dsa.pub. The key fingerprint is: 93:58:20:56:72:d7:bd:14:86:9f:42:aa:82:3d:f8:e5 localuser@mybox.home.com
It will prompt you for the location of the keyfile. Unless you have already created a keyfile in the default location, you can accept the default by pressing 'enter'.
Next it will ask you for a passphrase and ask you to confirm it. The idea behind what you should use for a passphrase is different from that of a password. Ideally, you should choose something unique and unguessable, just like your password, but it should probably be something much longer, like a whole sentence. Here are some examples of passphrases I've used in the past:
The right thing changes from state to state
the purpose of life is to give it purpose
They're not going to guess this passphrase!
The RIAA can just suck my big ass
It is never a good day at Teletron
Some passphrases that I've used have had as many as 60 characters along with punctuation and numbers. This makes the passphrase harder to guess. To give you an idea of how much more secure a passphrase is than a password. Consider this. Even if you narrowed down the number of words someone could use in a passphrase to 2000 potential words, if that person used 5 words in a sentence from that 2000 word set, it would mean there are 32,000,000,000,000,000 different combinations. Compare this with 6,095,689,385,410,816, which is the total possible combinations in an 8 character password using upper and lower case characters, numbers and punctuation (about 94 potential characters). So an 8 character password has 5.25 times less combinations than a 5 word passphrase. In actuality, most people choose words from a set of 10,000 or more words, bringing the complexity of a 5 word passphrase to 16,405 or more times greater than that of a 8 character password. So on average, the difficulty of cracking a passphrase is much greater than any password that could be used. Interestingly, the potential number of combinations of 8 word passphrase of someone with an adult vocabulary (8000 words or more) is almost equal to the number of 8 character password combinations multiplied by itself or about 16,777,216,000,000,000,000,000,000,000,000 combinations.
Don't use any famous quotes or phrases for your passphrase, they may be easily guessed by another person or by a brute force cracking program.
The reason why you would generate a keyfile is so that you can increase the security of your SSH session by not using your system password. When you generate a key, you are actually generating two key files. One private key and one public key, which is different from the private key. The private key should always stay on your local computer and you should take care not to lose it or let it fall into the wrong hands. Your public key can be put on the machines you want to connect to in a file called .ssh/authorized_keys. The public key is safe to be viewed by anybody and mathematically cannot be used to derive the private key. Its just like if I gave you a number 38,147,918,357 and asked you to find the numbers and operations I used to generate that number. There are nearly infinite possibilities.
Whenever you connect via ssh to a host that has your public key loaded in the authorized_keys file, it will use a challenge response type of authentication which uses your private key and public key to determine if you should be granted access to that computer It will ask you for your key passphrase though. But this is your local ssh process that is asking for your passphrase, not the ssh server on the remote side. It is asking to authenticate you according to data in your private key. Using key based authentication instead of system password authentication may not seem like much of a gain at first, but there are other benefits that will be explained later, such as logging in automatically from X windows.
Installing your public key manually
If you do not have the ssh-copy-id program available, then you must use this manual method for installing your ssh key on the remote host. Even if you do have the ssh-copy-id program, its good to do the manual installation at least once so that you have a good understanding of what is going on, because this is where a lot of people end up having problems.
Go ahead and copy your public key which is in ~/.ssh/id_dsa.pub to the remote machine.
scp ~/.ssh/id_dsa.pub username@arvo.suso.org:.ssh/authorized_keys
It will ask you for your system password on the remote machine and after authenticating it will transfer the file. You may have to create the .ssh directory in your home directory on the remote machine first. By the way, scp is a file transfer program that uses ssh. We'll talk more about it later.
Now when ssh to the remote machine, it should ask you for your key passphrase instead of your password. If it doesn't, it could be that the permissions and mode of the authorized_keys file and .ssh directory on the remote server need to be set more restrictively. You can do that with these commands on the remote server:
chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys
You can also put the public key in the remote authorized_keys file by simply copying it into your paste buffer, logging into the remote machine and pasting it directly into the file from an editor like vi, emacs or nano. I would recommend using the 'cat' program to view the contents of the public key file though because using less will end up breaking the single line into multiple lines.
cat ~/.ssh/id_dsa.pub
Installing your public key automatically
A newer way that you can quite easily install your public ssh key on a remote host is with the ssh-copy-id program like this:
ssh-copy-id yourusername@your.website.com
It will prompt you for your password on the remote host and take care of the rest. That was easy. So why didn't I just tell you how to use this program in the first place? Well, in my experience, many of the problems people have with ssh revolve around trying to get their ssh public key installed correctly. Its a good thing that they've made a program to do the dirty work for you, but in the interest of building your skills, you should at least do the manual install once so that you know what is involved.
Using the ssh-agent program
The true usefulness of using key based authentication comes in the use of the ssh-agent program. Usually, the ssh-agent program is a program that starts up before starting X windows and in turn starts X windows for you. All X windows programs inherit a connection back to the ssh-agent, including your terminal windows like Gnome Terminal, Konsole, xfce4-terminal, aterm, xterm and so on. What this means is that after you've started up X windows through ssh-agent, you can use the ssh-add program to add your passphrase one time to the agent and the agent will in turn pass this authentication information automatically every time you need to use your passphrase. So the next time you run:
ssh username@arvo.suso.org
you will be logged in automatically without having to enter a passphrase or password. Most recent distributions will automatically start ssh-agent when you login to X windows through a session manager like gdm (graphical login). I found that as of this writing the following distributions started ssh-agent by default.
Most distributions prior to about 2002 did not start it.
Don't worry if you don't see your distro listed in here. You can check if it is already running by running this command.
ps auxw
If there is an ssh-agent process listed there, then you can just start using it, otherwise, you should consult your distribution's documentation on OpenSSH and running the ssh-agent.
Once you've verified that ssh-agent is running, you can add your ssh key to it by running the ssh-add command:
ssh-add
If the program finds the DSA key that you created above, it will prompt you for the passphrase. Once you have done so it should tell you that it has added your identity to the ssh-agent:
Identity added: /home/username/.ssh/id_dsa (/home/username/.ssh/id_dsa)
Now you can try logging into that remote machine again and this time you will notice that it just logs you right in without prompting you for any password or passphrase.
To make adding your passphrase easier, you can add the ssh-add program to your desktop session startup programs and it will bring up a prompt in X windows to ask for your passphrase every time you login to your desktop. You should also have the gtk2-askpass program installed. Or x11-askpass. They are the real programs that actually prompt you for your password. ssh-add just runs them if its not being run in a terminal. Below is a screenshot of the Gnome Sessions Configuration dialog with ssh-add added to the startup programs.
Gnome Session with ssh-add program set to run and prompt for your key's passphrase
X11 Session Forwarding
One lesser known feature of X windows is its network transparency. It was designed to be able to transmit window and bitmap information over a network connection. So essentially you can login to a remote desktop machine and run some X windows program like Gnumeric, Gimp or even Firefox and the program will run on the remote computer, but will display its graphical output on your local computer.
To try this out, you will need an account on a remote computer that has X windows installed with some X windows applications. suso.org servers do not have any such programs so you will need to either login to one of your other workstations or another server that does have them. The key to making it work is using the -X option, which means "forward the X connection through the SSH connection". This is a form of tunneling.
ssh -X username@desktopmachine.domain.com
If this doesn't work, you may have to setup the SSH daemon on the remote computer to allow X11Forwarding, check that the following lines are set in /etc/ssh/sshd_config on that computer:
X11Forwarding yes X11DisplayOffset 10 X11UseLocalhost yes
For some newer programs and newer versions of X windows, you may need to use the -Y option instead for trusted X11 forwarding. Try using this option if your X11 windows program fails to start running with a message like this one that was for Gimp:
The program 'gimp-2.2' received an X Window System error. This probably reflects a bug in the program. The error was 'BadWindow (invalid Window parameter)'. (Details: serial 154 error_code 3 request_code 38 minor_code 0) (Note to programmers: normally, X errors are reported asynchronously; that is, you will receive the error a while after causing it. To debug your program, run it with the --sync command line option to change this behavior. You can then get a meaningful backtrace from your debugger if you break on the gdk_x_error() function.)
TCP Port Forwarding
Like X11 session forwarding, SSH can also forward other TCP application level ports both forward and backwards across the SSH session that you establish.
For example, you can setup a port forward for your connection from your home machine to arvo.suso.org so that it will take connections to localhost port 3306 and forward them to the remote side mysql.suso.org port 3306. Port 3306 is the port that the MySQL server listens on, so this would allow you to bypass the normal host checks that the MySQL server would make and allow you to run GUI MySQL programs on your local computer while using the database on your suso account. Here is the command to accomplish this:
ssh -L 3306:mysql.suso.org:3306 username@arvo.suso.org
The -L (which means Local port) takes one argument of
<local-port>:<connect-to-host>:<connect-to-port>
so you specify what host and port the connection will go to on the other side of the SSH connection. When you make a connection to the <local-port> port, it sends the data through the SSH connection and then connects to <connect-to-host>:<connect-to-port> on the other side. From the point of view of <connect-to-host>, its as if the connection came from the SSH server that you login to. In the case above, arvo.suso.org.
This is much like a VPN connection allows you to act like you are making connections from the remote network that you VPN into.
Take a moment to think of other useful connections you can make with this type of network tunnel.
Another useful one is for when you are away from home and can't send mail through your home ISP's mail server because it only allows local connections to block spam. You can create an SSH tunnel to an SSH server that is local to your ISP and then have your GUI mail client like Thunderbird make a connection to localhost port 8025 to send the mail. Here is the command to create the tunnel:
ssh -L 8025:smtp.homeisp.net:25 username@shell.homeisp.net
One thing to note is that non-root users do not normally have the ability to listen on network ports lower than 1024, so listening on port 25 would not work, thus we use 8025. It really doesn't matter, you can use any port as long as your email client can connect to it.
You can also reverse the direction and create a reverse port forward. This can be useful if you want to connect to a machine remotely to allow connections back in. For instance, I use this sometimes so that I can create a reverse port 22 (SSH) tunnel so that I can reconnect through SSH to a machine that is behind a firewall once I have gone away from that network.
ssh -R 8022:localhost:22 username@my.home.ip.address
This will connect to my home machine and start listening on port 8022 there. Once I get home, I can then connect back to the machine I created the connection from using the following command:
ssh -p 8022 username@localhost
Remember to use the right username for the machine that you started the tunnel from. It can get confusing. You also have to keep in mind that since you are connecting to the host called localhost, but its really a port going to a different SSH server, you may wind up with a different host key for localhost the next time you connect to localhost. In that case you would need to edit your .ssh/known_hosts file to remove the localhost line. You really should know more about SSH before doing this blindly.
As a final exercise, you can keep your reverse port forward open all the time by starting the connection with this loop:
while true ; do ssh -R 8022:localhost:22 suso@my.home.ip.address ; sleep 60 ; done
This way, if you happen to reboot your home machine, the reverse tunnel will try to reconnect after 60 seconds. Provided you've setup keys and your ssh-agent on the remote machine. ;-)
SOCKS5 proxying
So thats great and all, but eventually you are going to want to know how you can do tunneling without having to specify the address that you want to forward to.
This is accomplished through the -D SOCKS5 option.
ssh -D 9999 username@remotehost.net
Any application that supports the SOCKS5 protocol (and most of the big network programs do) can forward its network connection over SSH and dynamically forward to any hostname that you specify. So for a web browser, any URL that you type in the URL field, would be sent through the SSH tunnel. Firefox, Xchat, Gaim and many others all support using SOCKS5. The setting is usually under preferences in the connection settings.
Remember, in the words of Benjamin "Uncle Ben" Parker, with great power comes great responsibility. Just because you can get around firewalls and use other hosts for sending network traffic, doesn't mean that some system administrator isn't going to notice you.
Running Commands Over SSH
Sometimes you don't really want to run a shell like Bash on the host you are connecting to. Maybe you just want to run a command and exit. This is very simply accomplished by putting the command you wish to run at the end of your ssh connection command.
ssh username@remotehost.net ls -l /
This will probably generate output similar to the following.
total 220 drwxr-xr-x 2 root root 4096 Nov 9 04:08 bin drwxr-xr-x 3 root root 4096 Nov 11 09:29 boot drwxr-xr-x 23 root root 122880 Nov 14 02:36 dev drwxr-xr-x 68 root root 12288 Jan 10 04:03 etc drwxr-xr-x 189 root root 4096 Jan 9 00:40 home drwxr-xr-x 2 root root 4096 Mar 12 2004 initrd drwxr-xr-x 9 root root 4096 Nov 9 04:07 lib drwx------ 2 root root 16384 Sep 26 2004 lost+found drwxr-xr-x 2 root root 4096 Apr 14 2004 misc drwxr-xr-x 6 root root 4096 Nov 12 02:11 mnt drwxr-xr-x 3 root root 4096 Oct 15 22:17 opt dr-xr-xr-x 307 root root 0 Nov 14 02:36 proc drwx------ 44 root root 8192 Jan 9 16:23 root drwxr-xr-x 2 root root 8192 Nov 9 04:08 sbin drwxr-xr-x 2 root root 4096 Mar 12 2004 selinux drwxr-xr-x 9 root root 0 Nov 14 02:36 sys drwxrwxrwt 20 root root 4096 Jan 10 06:46 tmp drwxr-xr-x 17 root root 4096 Dec 7 2004 usr drwxr-xr-x 26 root root 4096 Jan 10 2005 var
Then you can process the output however you want using the normal shell conventions.
You can also do something called forced-command where you force any login attempt to run a specific command regardless of what is specified on the command line by the client.
To do this, you put this variable and the command you want to force in the authorized_keys file on the remote host:
command="/usr/bin/backup" ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIEAvna.....
Put the variable before the start of the line for the key. There are other variables you can use here like from="" to allow only from a specific host. These variables can be put together separated by commas.
(This space is intentionally left blank)
Using SCP
SCP is basically a program that uses the SSH protocol to send files between hosts over and encrypted connection. You can transfer files from your local computer to a remote host or vice versa or even from a remote host to another remote host.
Here is a basic command that copies a file called report.doc from the local computer to a file by the same name on the remote computer.
scp report.doc username@remote.host.net:
Note how the lack of a destination filename just preserves the original name of the file. This is also the case if the remote destination includes the path to a directory on the remote host.
To copy the file back from the server, you just reverse the from and to.
scp username@remote.host.net:report.doc report.doc
If you want to specify a new name for the file on the remote computer, simply give the name after the colon on the to side.
scp report.doc username@remote.host.net:monday.doc
Or if you want to copy it to a directory relative to the home directory for the remote user specified.
scp report.doc username@remote.host.net:reports/monday.doc
You can also use fullpaths which are preceded with a /.
To copy a whole directory recursively to a remote location, use the -r option. The following command copies a directory named mail to the home directory of the user on the remote computer.
scp -r mail username@remote.host.net:
Sometimes you will want to preserve the timestamps of the files and directories and if possible, the users, groups and permissions. To do this, use the -p option.
scp -rp mail username@remote.host.net:
Keeping Your SSH Session Alive
Sometimes you may have trouble keeping your SSH session up and idle. For whatever reason, the connection just dies after X minutes of inactivity. Usually this happens because there is a firewall between you and the internet that is configured to only keep stateful connections in its memory for 15 or so minutes.
Fortunately, in recent versions of OpenSSH, there is a fix for this problem. Simply put the following:
Host * Protocol 2 TCPKeepAlive yes ServerAliveInterval 60
in the file
The file above can be used for any client side SSH configuration. See the ssh_config man page for more details. The 'TCPKeepAlive yes' directive tells the ssh client that it should send a little bit of data over the connection periodically to let the server know that it is still there. 'ServerAliveInterval 60' sets this time period for these messages to 60 seconds. This tricks many firewalls that would otherwise drop the connection, to keep your connection going.
Ending your SSH session
All good things come to an end. And there are many common ways to end your SSH session.
exit
logout
(Ctrl-d)
The last one is actually the user pressing the 'Ctrl' key and the letter 'd' at the same time. These all are ways of terminating the SSH session from the server side. They usually exit the shell which in turn logs you off the machine.
What you may not know, is that there is another way to close an SSH session. This is useful if you lose connectivity with the machine and you have no way of ending your shell session. For example, this happens momentarily if you stay logged into a machine while it is shutdown. SSH has its own command line escape sequences. These can be used to end connections, create new port forwards or list current ones and a few other functions. To end a connection even when you don't have a command prompt, type return twice (for good measure) and then the sequence '~.'. That's a tilde followed by a period.
(RETURN) (RETURN) ~.
This will terminate the SSH connection from the client end instead of the server end.
Happy SSH'ing!
External References
Here are some links where you can find more information about SSH
Credits