Alien's Bash Tutorial

Written by Billy Wideling <-> alien a koping d net

Modifications: 20060717 Alf Lacis, alfredo4570 a gmail d com.  Original .txt file version from http://www.usc.edu/~lhl/tutorials/unix/bash_tutor/aliens_bash_tutorial.txt, copied here.  Converted to HTML, inserted a clickable Table of Contents and Index of *nix commands, local 'targets', spell checked, and tabled some pictures.
20080817 Fixed formatting inconsistencies by using div, pre and tt styles.

First you probably need to read a UNIX command bible to really understand this tutorial, but I will try to make it as clear as possible, there is about 100-150 UNIX commands explained later in this tutorial.

You are to have some UNIX experience before starting on this tutorial, so if you feel that you have UNIX/Linux experience feel free to start to learn here.

What I included here is general shell scripting, most common other things and some UNIX commands.

Here's the most common shell types:

bash  = Bourne again shell
sh    = shell
csh   = C shell
tcsh  = Tenex C shell (not tab-completion-extended C shell)
tclsh = Tcl shell
ksh   = korn shell
ash   = a shell
bsh   = bourne shell ? (in most Linux distributions it's a link to /bin/ash)
zsh   = the Z shell (it's what it's manual page tells about it .. :/ )

Table Of Contents
1 - What you already know
2 - Where to start
3 - Beginning techniques
4 - Other techniques
5 - Practical Scripting Examples
6 - Customize your system and shell
7 - Networking
8 - The Init and system scripts
9 - Basic Linux/UNIX commands and operations
10 - Other Frequently asked questions with answers
11 - Basics of the common UNIX and Linux text editors
12 - Closing

===============================================================================

1 - What you already know. (should know)

============================================================= Table Of Contents

Here we go, bash scripting is nothing more than combining lots of UNIX commands to do things for you, you can even make simple games in bash (just UNIX commands) or as in normal cases, batch files to control things in your computer.

There is a variety of easier and harder examples in the beginning of this tutorial, I've done it this way to make it easier for people to get the general picture, so they will get more of the "aha!" experiences in the later chapters of this tutorial.

What bash or any scripting language does is to call for premade programs that lives in your computer. So when you write a command in a script you are calling a command that is a part of the system. That is why this tutorial will be just as much a Linux and UNIX tutorial as a shell scripting tutorial.

I will however not take up much about The X Windows System in this tutorial, for the simple reason that a Window Manager does nothing else than display programs.

This means that a Window Manager is like a graphical shell for the system. You can do all in this tutorial from any terminal emulator in a Linux Graphical Environment (The X Windows System).

A terminal emulator would be such as: Eterm, xterm, axvt, rxvt, kterm, etc. A terminal emulator lets you get up a terminal with a command prompt in a graphical window.

Shell command separator/control characters:

|  = pipe will take the first commands stdout as the second commands stdin.
|| = OR if first command is false, it will take the second.
|= = OR IS (mostly used in if statements)
&& = AND if first command is true, it will execute the second one.
!  = NOT (mostly used in if and test statements), but as a shell-command
     it opens a shell to run the command (ex. `! echo foo`)
!= = NOT IS (mostly used in if statements)
!$ = last commands last argument
!! = repeat last command
=  = IS (mostly used in if statements)
;  = will separate 2 commands as if they were written on separate command lines
;; = end of a case function in a case statement. (see 'case' further down)
$  = prefix to a variable like "$myvar"
$! = PID of the last child process.
$$ = PID of current process (PID == Process ID)
$0 = Shows program that owns the current process.
$1 = First argument supplied after the program/function on execution.
$2 = Second argument supplied after the program/function on execution. ($3 etc.)
$# = Shows the number of arguments.
$? = Any argument (good to use in 'if' statements)
$- = current option flags (I never ever had to use this one)
$_ = Last argument/Command
$* = All arguments
$@ = All arguments
#  = remmed line, anything on a line after "#" will be overlooked by the script
{  = start braces (starts a function)
}  = end braces   (ends a function)
[  = start bracket (multiple-argument specifiers)
]  = end bracket (multiple-argument specifiers)
@  = $@ is equivalent to "$1" "$2" etc. (all arguments)
*  = wild card (* can substitute any number of characters)
?  = wild card (? can substitute any single character)
"  = quote
'  = precise quote. (Will even include "'s in the quote)
`  = command quote. (variable=`ls -la` doing $variable will show the dir list)
.  = dot will read and execute commands from a file, ( . .bashrc )
&  = and. as suffix to executed file makes it go to the background(./program &)
0> = stdin stream director (I never seen this used in any script)
1> = stdout stream director (standard output)
2> = stderr stream director (standard error output)
%  = job character, %1 = fg job 1, %2 = fg job 2, etc.
>> = stream director append to a file
<< = stdin stream director. (cat > file << EOF ; anything ; EOF)
>  = stream director that will start at the top of the file
    (in if statements < and > may be used as greater-than
    and lesser-than, as: if [ "$1" >= "2" ])
\  = back-slash, takes away any special meaning with a character,
     \$var will not be treated as a variable.
     (and a new line will not be treated as a new line)
     Also a \ before a command, removes any alias on the command as: \rm
>& = stream director to stream director, ie. echo "a" 1>/dev/null 2>&1
     this directs 2> to the same place as 1>

Here is the basic UNIX or rather Linux directory structure:

                                / (system root)
 _______________________________|____________________________________
 |    |     |    |     |    |       |         |    |      |    |    |
bin/ boot/ dev/ etc/ home/ lib/ lost+found/ proc/ root/ sbin/ usr/ var/
 |    |     |    |     |    |       |         |    |      |    |    |
 |    |     |    |     |    |       |         |    |      |    |    |-> various
 |    |     |    |     |    |       |         |    |      |    |
 |    |     |    |     |    |       |         |    |      |    |-> Read later..
 |    |     |    |     |    |       |         |    |      |
 |    |     |    |     |    |       |         |    |      |-> Superuser Binaries
 |    |     |    |     |    |       |         |    |
 |    |     |    |     |    |       |         |    |-> User roots home dir
 |    |     |    |     |    |       |         |
 |    |     |    |     |    |       |         |-> system info etc.
 |    |     |    |     |    |       |
 |    |     |    |     |    |       |-> Orphan files (look here after crashes)
 |    |     |    |     |    |
 |    |     |    |     |    |-> System / programming libraries
 |    |     |    |     |
 |    |     |    |     |-> Contains the user accounts home directories
 |    |     |    |
 |    |     |    |-> System configuration files.
 |    |     |
 |    |     |-> Devices
 |    |
 |    |-> The kernel and kernel maps.
 |
 |-> Executable files. (binaries)

The /usr directory contains a whole lot of things, mainly user accessible things, like binaries in /usr/local/bin/ and /usr/bin/ also libraries in /usr/lib/ and /usr/local/lib/.

The kernel source should also be under /usr, in /usr/src/linux/ But more about that later.

Here's an example of the following files locations:

/dev/null
/dev/fd0
/etc/passwd
/home/alien/.profile
/usr/local/bin/BitchX
                                /
 _______________________________|____________________________________
 |    |     |    |     |    |       |         |    |      |    |    |
bin/ boot/ dev/ etc/ home/ lib/ lost+found/ proc/ root/ sbin/ usr/ var/
            |    |     |                                       |
            |    |   alien/                                  local/
            |    |     |                                       |
            |    |     |-> .profile                            |
            |    |-> passwd                                   bin/
            |                                                  |
            |-> null                                           |-> BitchX
            |-> fd0

And a final example that's a bit more stripped, just in case you are really new to computers. For these following files, the locations are:

/dev/null
/dev/audio
/dev/hda1
/etc/passwd
/etc/shadow
/home/alien/.profile
/home/alien/tmp/somefile
/home/user/.bash_profile
/usr/local/bin/BitchX
/sbin/shutdown
                               /
  _____________________________|_____________________________
  |              |             |            |              |
 dev/           etc/         home/-----    usr/          sbin/
  |              |             |      |     |              |
  |-> null       |             |      |   local/           |-> shutdown
  |-> audio      |             |      |     |
  |-> hda1       |             |      |    bin/
                 |-> passwd  alien/   |     |
                 |-> shadow    |     user/  |-> BitchX
                               |      |
                               |      |-> .bash_profile
                               |
                               |-> .profile
                               |
                              tmp/
                               |
                               |-> somefile

This is the same structure as on any Operating System that uses directories, Though some Operating Systems may call the / directory C: and some other may call it HD etc. and of course some of the directory names in Linux/UNIX are UNIX specific.

No further explanation should be necessary.

After reading this tutorial, browse around the system and try to learn what all the files does, just don't remove any files you didn't put there until you're ABSOLUTELY sure of what you are doing.


Here's a few UNIX commands just for illustration:

echo
======
        echo will *echo* anything you add to it like this:

        alien:~$ echo "blah"
        blah
        alien:~$

        To get it to echo without a new line add the suffix -n
        like this:

        alien:~$ echo -n "blah "
        blah alien:~$

        I'll get back to why you want to do "-n" sometimes in a while.

read
======
        read will read from the keyboard (stdin) and save it as a variable
        the variable name goes after the read command, like this:

        alien:~$ read myvar
        <here I type say "blah">
        alien:~$ echo $myvar
        blah
        alien:~$

        To combine these two commands (echo and read) in a small script
        line, it can look like this:

        alien:~$ echo -n "password: " ; read pass ; echo "Your pass is $pass"
        password: <here I type "mypass">
        Your pass is mypass
        alien:~$

        Get the basic idea ?

Anyway, here are some commands that you should know before moving on with this tutorial -

[*] after == important to know.
[X] after == very basics will do.

ls      [*]     Ex: ls -la              Long directory listing.
echo    [*]     Ex: echo "foo"          Does what it says.
cat     [*]     Ex: cat /etc/passwd     Dump out the content of a file.
less    [X]     Ex: less /etc/passwd    Scroll up and down in a file (q = exit)
head    [X]     Ex: head -5 /etc/passwd Get the 5 (-5) first lines of a file.
tail    [X]     Ex: tail -7 /etc/passwd Get the 7 (-7) last lines of a file.
grep    [*]     Ex: grep x /etc/issue   Dump lines containing x from /etc/issue
chmod   [*]     Ex: chmod a+x file      Give everyone executable rights to file
chown   [X]     Ex: chown root file     Change owner of file to root.

(cd     [-]     Ex: cd /etc             Change Directory to /etc)

Some applications you need to know how to operate (basics will do) :

any text editor (preferably emacs or vi - they are explained last in this file)
telnet          Ex: telnet 127.0.0.1    Opens a connection to IP 127.0.0.1
lynx            Ex: lynx http://foo.bar A command line based web browser.
ftp (ncftp)     Ex: ncftp ftp://foo.bar A command line based ftp client.
ssh             Ex: ssh 127.0.0.1       Opens a secure connection to 127.0.0.1

These are all explained fully later in this tutorial.


Now don't sit there and ask yourself how's going to teach you the commands or applications I just listed here above. use the manual pages. like this:

man echo

that will get you the full manual on the command echo :) man works the same way with applications that you have the manual pages for.

To get out of the manual page just press the letter q. q quits it and gets you back to the command line prompt. man uses all the normal less commands.

Or read further down in this tutorial in the basic Linux/UNIX commands and operations section (9).


The key to shell scripting just as with any programming language/Operating System is to REALLY understand what you are doing, so do read this file more than once, and don't read it too fast.
Take your time and let it sink in, so you know what it's all about, and do take time to read manual pages and do some playing with the commands so you learn them.

Now that should be enough of what you *should* know before starting to learn UNIX shell scripting.

So here we go.......

===============================================================================

2 - Where to start

============================================================= Table Of Contents

You should always start with very simple scripts that you really don't have any practical use for but still *could* be of practical use =)

As for first let's make what we already know to a *real* executable script. Open a text editor (name the file myscript.sh) and type this:

#!/bin/bash

echo -n "password: "
read pass
echo "Your pass is $pass"

save & exit --- then do this command:

chmod u+x myscript.sh

Then we can execute it:

alien:~$ ./myscript.sh
password: <type what you want>
Your pass is <what you typed>
alien:~$

The "#!/bin/bash" at the start of the file is to let the script know what shell type it should use.

The "chmod u+x myscript.sh" is to make it executable.
(English: change-mode user+execute-right-on myscript.sh) ..... read the manual pages on chmod for more info on it =)


Take a lot of time to play around in your system, open files, figure out what they do (but don't edit or remove them).

Take time also to learn some good text editor, that's important. Learn, emacs or vi, those are by most people considered the absolutely best, but jed, joe, elvis, pico or any simple editor like that will do just fine for now.

emacs and vi are explained later in this tutorial.


Another thing before moving on is that you can export a variable from a script.

Say that you have the variable $var in a script and want to export it to the system for use with some other script or something, you can do: export var .

Like this little script:

#!/bin/bash

VAR="10"
export VAR

Note: VAR="10" can not be written as VAR = "10", because it's 'whitespace-sensitive'.


But more to how to make scripts in a second, I just thought that this would be a good time to enlighten you about this.

So here we go ....

===============================================================================

3 - Beginning techniques.

============================================================= Table Of Contents

First off I'm going to show how to count in bash or how to use your command line as a calculator, which is really easy and useful.

alien:~$ echo $[ 4 * 2 ]
8
alien:~$

or another example:

alien:~$ echo $[ 10 + 5 ]
15
alien:~$

Easy ? .... I think it is =)

The internal calculator can also be used like this:

alien:~$ echo $(( 10 + 5 ))
15
alien:~$

The second way of using the internal shell calculator is here just so you don't get confused if you see it used that way sometime.


Now I'd like to show the *string comparing* with "if" statements, which can be a little hard at first contact, but as soon as you get familiar with it, it won't be any problem. So here's an example.

#!/bin/bash

echo -n "enter a name: "
read var1
echo -n "enter another name: "
read var2

if [ "$var1" = "$var2" ]; then
echo "The names are the same"
else
echo "The names were not the same"
fi

exit 0
Note: fi is the ending of if, just like a } is the ending of a {.
"exit 0" terminates the script correctly and returns you to the prompt.
Another note is that instead of " = " you can use " -eq " to test if 2 expressions are equal, or " -eg " to check if 2 integers are equal, etc.

It should also be said that a variable say "$var" can be written as this: ${var}, just so you know if you see it done that way in some scripts, but here we will use the $var way.

AL: ${var} is especially useful where parts of a variable name have to be joined up, e.g., if $foo contains Hello then var=${foo}XYX will set $var to HelloXYZ.

This example if executed looks like this:
(Matching names)

alien:~$ ./script1.sh
enter a name: smurf
enter another name: smurf
The names are the same
alien:~$

(Non-matching names)

alien:~$ ./script1.sh
enter a name: smurf
enter another name: guru
The names were not the same
alien:~$

You can compare any 2 strings with this, as this *mid script example*:

...
if [ "$user" = "gnu" ]; then
echo "Hello user gnu !"
else
echo "I don't know you."
fi
...

This compares a variable with a static string which you can set to anything. You can also do this the other way around.

...
if [ "$user" != "gnu" ]; then
echo "I don't know you."
else
echo "Hello user gnu !"
fi
...

The "!=" means NOT-IS, in clear text if the 2 strings are not a match. As the above example in straight English:

...
if the variable don't match the word gnu, then
say "I don't know you."
in other cases
say "Hello user gnu !"
...

If you think that a variable may not contain anything and you wanna avoid it showing you errors you can add an x (or any other character) as the first character to both the statements to test with if, like this to compare $one with -x:

...
if [ "x$one" = "x-x" ]; then
echo "$one is -x"
else
echo "$one is not -x"
fi
...

In plain English:

...
if (contents of $one) equals -x (suppress error messages if any), then
say (contents of $one) is -x
in other cases
say (contents of $one) is not -x
...

This previous way is actually quite old, and only a precaution, say this:

...
echo -n "enter a number: "
read foo
if [ $foo = 2 ]; then
echo ok foo
fi
...

Now, if you with this example don't enter any number there will be nothing there for if to compare with, not even a blank "", since we're not using quotes, but as this:

...
echo -n "enter a number: "
read foo
if [ x$foo = x2 ]; then
echo ok foo
fi
...

There will always be something, because if $foo is nothing there is still x. Just read a couple of times and you'll get it.

You can also test if a variable contains anything at all like this:

...
echo -n "enter a number: "
read foo
[ -n $foo ] &&
echo ok foo
...

This uses the same options as the test command, so "-z" will return true if the variable is empty, -z will return true if the variable is not empty etc. It's ok if you don't understand this right now .... I've added this for the second time readers.

You can also test if a command turns out as true, like this:

...
if echo "foo" >/dev/null; then
echo "foo"
else
echo "bar"
fi
...

Here if will check if foo echos to /dev/null, and if so, then it will print out foo and if foo didn't echo to /dev/null, it'll print out the word bar.

Another and perhaps *cleaner* way of doing the same is this:

...
if (echo "foo" >/dev/null); then
echo "foo"
else
echo "bar"
fi
...

It's the exact same thing but with parentheses around the command, it looks much cleaner ... and so the code is easier to follow.

You can also make if think 'if this is a match or that is a match', like if the variable is one of two options do one thing else do another. Like this:

...
if [ "$user" = "gnu" -o "$user" = "ung" ]; then
echo "Hello $user !"
else
echo "I never heard of $user..."
fi
...

The "-o" means OR in an if statement, so here is the example in plain English:

...
if the variable matches the word gnu or matches the word ung, then
say "Hello word !" (the word is the variable, now gnu or ung)
in other cases
say "I never heard of word..." (the word is whatever the variable is set to)
...
Note: The quotes are needed in an if statement in case the strings or variables it's suppose to compare is empty, since

if [ foo =  ]; then

would produce a syntax error, but

if [ "foo" = "" ]; then

would not.


The -o can also be made with "] || [", so that:

if [ "$user" = "gnu" -o "$user" = "ung" ]; then

can also be expressed as this:

if [ "$user" = "gnu" ] || [ "$user" = "ung" ]; then

You don't really need to remember that, but for the knowledge I decided to make a note out of that anyway, mostly for the more experienced readers of this tutorial, and for the readers that have read it several times.


You can also set static text in a variable, which is really easy:

#!/bin/bash
anyvar="hello world"
echo "$anyvar"
exit 0

Which executed would look like this:

alien:~$ ./myscript
hello world
alien:~$

Easy enough ? =)


Loops

Now let's move on to "for" and common for loops.

I am actually only going to show one sort of for loop example, of the reason that at this stage no more is needed, and would only confuse. As a note, for loops can be used (as soon shown) to import strings from a file to be used as variables in the script.

Now, here's the example:

#!/bin/bash
for VAR in `cat list.txt`; do
echo "$VAR was found in list.txt"
done
exit 0
Note: "done" terminates the loop when finished.
"in" and "do" are like bash *grammar*, I'll explain that later.
In the `cat list.txt` part, the `s around the command will make sure the script/line executes that part as a command, another way of doing this is to: $(cat list.txt) which has the same effect.
That's just a note so you wont get confused if you see it used that way some time.

The previous script example is dependent on that there is a file called list.txt, so let's make such, and fill it with something like this:

$ cat list.txt
123 234 345
456 567 678
789 890

Then the executed script would look like this:

alien:~$ ./script2.sh
123 was found in list.txt
234 was found in list.txt
345 was found in list.txt
456 was found in list.txt
567 was found in list.txt
678 was found in list.txt
789 was found in list.txt
890 was found in list.txt
alien:~$

Note: A space in a file read by a for loop is taken the same way as a new line.


Here is another example, with a for loop with an if statement:

#!/bin/bash

for VAR3 in `cat list.txt`; do
if [ "$VAR3" = "789" ]; then
echo
echo "Match was found ($VAR)"
echo
fi
done

exit 0

And executed that looks like this:

alien:~$ ./script3.sh

Match was found (789)

alien:~$

If you have read this in a calm fashion it should be quite clear to you so far, but before I move on to real practice examples I will explain the while loop, and some, more which can be used as to count and more, for various purposes, as you will see. You don't have to *understand* all of how this works, but you should at least learn it.

So here we go on an example with while:

#!/bin/bash

count="0"
max="10"

while [ $count != $max ]; do count=`expr $count + 1`
        echo "We are now at number: $count"
done

exit 0

Note: expr is a calculator command, you can read more about it later in this tutorial.

This in plain English reads the following:

make variable "count" hold the number 0
make variable "max" hold the number 10

while 0 is not 10, do add 1 to 0 (each loop until it is 10)
say "We are now at number: $count" (each time 1 is added as long as we are
in the loop)
end the loop
return to the prompt command line.

Which executed looks like, (you guessed it), this:

alien:~$ ./count.sh
We are now at number: 1
We are now at number: 2
We are now at number: 3
We are now at number: 4
We are now at number: 5
We are now at number: 6
We are now at number: 7
We are now at number: 8
We are now at number: 9
We are now at number: 10
alien:~$

Here is another example of a while loop.

#!/bin/bash

agreement=
while [ x$agreement = x ]; do
    echo
    echo -n "Do you agree with this ? [yes or no]: "
    read yesnoanswer
    case $yesnoanswer in
        y* | Y*)
                agreement=1
                ;;
        n* | n*)
                echo "If you don't agree, you can't install this software";
                echo
                exit 1
                ;;
    esac
done

echo "agreed"
echo

This in plain English reads the following:

Make an unknown variable named agreement
while the unknown variable is unknown and doesn't match the case,
say "Do you agree with this ? [yes or no]: "
read the answer into the "yesnoanswer" variable.
make a case and check the "yesnoanswer" variable for any words beginning
with y or Y, and if so, skip the rest and go on with the script
and say "agreed".
if it doesn't begin with y or Y, check if it starts with n or N.
If it does start with a n or N, then say:
"If you don't agree, you can't install this software"
and quit the script.

Which executed looks like this:

alien:~$ ./agree.sh

Do you agree with this ? [yes or no]: something

Do you agree with this ? [yes or no]: yes
agreed

Executed again, but with no as the answer:

alien:~$ ./agree.sh

Do you agree with this ? [yes or no]: nothing
If you don't agree, you can't install this software

alien:~$

Note that "nothing" begins with n and therefore matches what the script is looking for, y or Y, and n or N.

Also see later in the tutorial about case statements.


Functions

Now I'm going to explain shortly about functions in bash.

A function is like a script within the script, or you could say that you make your own little command that can be used in a script. It's not as hard as it sounds though.

So here we go on a example:

#!/bin/bash

function myfunk {
echo
echo "hello"
echo "this is my function"
echo "which I will display twice"
}

myfunk
myfunk

exit 0

Which executed looks like this:

alien:~$ ./funk.sh

hello
this is my function
which I will display twice

hello
this is my function
which I will display twice
alien:~$

Another example of functions can look like this:

#!/bin/bash

myvar="$1"
var2="$2"

if [ "$myvar" = "" ]; then
echo "Usage: $0 <integer> <integer>"
exit 0
fi

function myfunk {
expr $1 + $2
}

myfunk $myvar $var2

exit 0

Which executed looks like this:
Without any arguments:

alien:~$ ./funk.sh
Usage: ./funk.sh <integer> <integer>

With arguments:

alien:~$ ./funk.sh 12 3
15
alien:~$

Note: the $1 and $2 in the function is in fact the first and second argument supplied after the function name when it's called for within the script, so you could say that a function is like a separate script in the main script.


Yet another example of a function is this:

#!/bin/bash

myvar="$1"

if [ "$myvar" = "" ]; then
echo "Usage: $0 <number>"
exit 0
fi

function calcfunc { expr 12 + $1 ; }

myvar2=`calcfunc 5`

echo "welcome"
echo "Now we will calculate 12 + 5 * $myvar"

echo "the answer is `expr $myvar2 '*' $myvar`"

Which executed looks like this:
Without any arguments:

alien:~$ ./funk.sh
Usage: ./funk.sh <number>
alien:~$

And with arguments:

alien:~$ ./funk.sh 23
welcome
Now we will calculate 12 + 5 * 23
the answer is 391
alien:~$

And for the sake of knowledge it should also be said that a function can be declared in the following ways as well:

#!/bin/bash

function foo() {
echo "hello world"
}

foo
#!/bin/bash

foo () {
echo "hello world"
}

foo

Note that the parentheses after the function name are the new thing here.
It's used exactly the same way as without the parentheses, I just added that here so that you wont get confused if you see it made that way sometime.


So if you make a function, to call for it (to make use of it), just use the the functions name just as if it had been a command.

If there is anything that's uncertain at this point, go back and read it again, until you understand it, or at least get the basic idea. =)

===============================================================================

4 - Other techniques.

============================================================= Table Of Contents

Now let's move on to a little bit more advanced shell scripting.
Actually it's not that advanced, just more hard to keep in order, but let us leave that to the head of the beholder..... errr
Anyway, let's not make this harder than it is, so here we go, with a script example:

#!/bin/bash

> file1.c

cat >> file1.c << EOF
#include <stdio.h>
int main ( void )
{
  printf("Hello world\n");
  return 0;
}
EOF

cc file1.c -o file1 || gcc -o file1 file1.c
./file1

rm -f file1.c file1

exit 0

And here as follows, is an semi-English translation of the script:

echo nothing to file1.c to create it.

cat to file1.c what comes here after in between the "EOF"'s
// --- a short hello world program in C code --- //

try if there is a 'cc', if not then use 'gcc'
Execute the newly compiled file

remove file1.c and file1

exit the script.

This can be very useful, since bash do have it's limitations, so if you ever need something more powerful or just something else, you can always do like the script told.

Another little trick with the same thing in a script is:

more << EOF
Here you can type whatever,
like an agreement text or something.
EOF

Play around with it.


Here let's have a look at the case command. The case command, like if, ends with the command backwards.
So that what starts with case ends with esac. Here's an example of case:

#!/bin/bash

case "$1" in
    foo)
    echo "foo was written"
    ;;
    bar)
    echo "bar was written"
    ;;
    something-else)
    echo "something-else was written"
    ;;
esac

This is the same as saying:

....
if [ "$1" = "foo" ];then
echo "foo written"
fi
if [ "$1" = "bar" ];then
echo "bar was written"
fi

etc.
....

so case is far shorter if you have a lot of arguments.

Here's a better example:

#!/bin/bash

case "$1" in
    --help)
    echo "Usage: $0 [--help] [--port <port>] <host> [--time]"
    ;;
    --port)
    telnet $3 $2
    ;;
    --time)
    date
    ;;
esac

This is not very hard to learn,

case the first argument vector ($1) in
first-possible-match)
if it matches do ........
close the ) with ;;
etc. down to "esac"

Really not much more to say about the case command at this point.


Now let's have a REALLY quick look at the command sed, ('string editor') which is used to edit and reformat text. Say now that you have a file called tmp that contains the following:

http://www.metacrawler.com
http://www.yahoo.com
http://www.webcrawler.com

and you want to change all the "www"'s to "ftp", then you do like this:

sed 's/www/ftp/g' tmp

and if you want to store the changes to a file you can do:

sed 's/www/ftp/g' tmp > tmp2

This is not sed's only use, but for sure it's what it's most used for.

Here's just one other really simple thing sed could be used as:

sed -n 3 p /etc/passwd

This will print out the 3rd line of the /etc/passwd file.


Now let's take up a really interesting command dialog, that is a command with which you can create 'ncurses' dialog boxes.
Ncurses dialog boxes are what one would call 'console graphics' or 'ascii color graphics', if you ever seen a blue background and a gray box asking questions, with an <OK> and <Cancel> button, while running something in a console you have seen an ncurses dialog box.

Now here is a small script example of a dialog box:

#!/bin/bash

dialog --backtitle "My first dialog" \
       --title "Main menu" \
       --menu "Make your choice" 13 60 6 \
        1 "First option" \
        2 "Second option" \
        3 "Exit" 2> .tempfile
        output=`cat .tempfile`
        rm -f .tempfile

if [ "$output" = "1" ]; then
dialog --msgbox "First option was entered" 5 40
fi

if [ "$output" = "2" ]; then
dialog --msgbox "Second option was entered" 5 40
fi

exit 0

Here is another very small example with dialog boxes:

#!/bin/bash

dialog --yesno "Do you agree, jada jada" 10 50 && \
dialog --yesno "ok you agreed" 10 50 || \
dialog --yesno "ok fine, leave then ..." 10 50
-------------------------------------------------------------------------------
In English:
If the first one (Do you agree, jada jada) returns 'true' (yes)
then it walks on to the next (ok you agreed),
and if any of those first two returns 'false' (no) it will display
the last (ok fine, leave then ...).
Note:
The back slashes"\" are used to say "no new line" as in what comes on the next line will be treated as if it were on the same line as the last line, the "\" really means that the next character's special meaning (in this case the new lines) is overlooked.
Just in case you didn't understand, the numbers after, like 10 50:
dialog --yesno "ok fine, leave then ..." 10 50
is the geometry of the window. First number is height and the second width.
Another note being that the command "Xdialog" works the same as dialog, but I wont take that up here because it doesn't come as default with any other Linux distribution than Mandrake, as far as I know.
A final note is that the dialog command is getting to be out-dated but is still the most used, the newer version of it is named whiptail and works the same as dialog, but looks slightly different.

Now we have covered most of it, so let's take up some small tricks, that bash allows you to do, here follows what it does, and then the code example:

Here we wanna check if you have a directory called /usr/local/bin:

if [ -d /usr/local/bin ]; then
cp file /usr/local/bin/
else
echo "NO !!"
fi

Another way of doing the same thing is this:

test -d /usr/local/bin && cp file /usr/local/bin/ || echo "NO !!"

Or:

ls /usr/local/bin/ && cp file /usr/local/bin/ || echo "NO !!"

The last way is a bit messy, but a lot smaller than the first one, but here's yet another way that's small and less messy:

ls /usr/local/bin/ 1>/dev/null 2>&1 && cp file /usr/local/bin/ || echo "NO !!"

That might look really weird at first sight, but it's easy if you break it down and look at it:

ls /usr/local/bin/ <<==== lists /usr/local/bin/
1>/dev/null        <<==== sends the contents of the listing to 'the black hole'
2>&1               <<==== sends any errors the same way... to 'the black hole'
                          (same thing as to say 2>/dev/null)
&&                 <<==== if the first command worked, we will go on here.
cp file /usr/local/bin/   <<==== copy file to /usr/local/bin/
||                 <<==== if the  first command didn't work...
                          we go on here instead.
echo "NO !!"       <<==== what it says ... say NO !!

as this:

If `ls` can list /usr/local/bin/ next command can be executed, OR if not
it will echo "NO !!", and all listings/errors are being sent to /dev/null
the 'black hole' of a UNIX/Linux.

To prevent that a script is being executed more the once at the same time for some reason you may wanna let the script make a 'lock' file. This is very easy to do:

#!/bin/bash
ls script.lock 1>/dev/null 2>&1 && exit 0 && echo "lockfile detected"
> script.lock
echo "Here is where the script should be"
rm -f script.lock
exit 0
-------------------------------------------------------------------------------
In English:
Here we first check if there is a lockfile, and if there is we terminate the
script and say that a lockfile was detected.
If there is no lockfile, we create one and start to execute the rest of the
script.
At the end of the script we remove the lockfile, so that the script can be
executed again.
All this is just to prevent the same script to be run twice at the same time,
which can be a good thing if your script does something that cant be done
twice at the same time, as mounting a hard drive/cd-rom, using sound or
anything like that.

Another neat little trick is if you from within a script are going to create temporary files that you want unique (to not overwrite some other files anywhere, wherever the script may get executed), then you can use a predefined variable called $$, which is the 'process ID' or 'pid' of the executing shell, like this:

#!/bin/bash
echo "ls" >.tmp.$$
echo "-la" >.tmp2.$$
one=`cat .tmp.$$`
two=`cat .tmp2.$$`
$one $two
rm -f .tmp.$$ .tmp2.$$

This will make a file called .tmp.<pid of script> containing the word "ls", then it will make a file called .tmp2.<pid of script> containing "-la".
After that it makes 2 variables, each one when being called will concatenate ('cat') one of the .tmp.* files each. At the end we have "$one $two" that will work the same as if we had printed:

ls -la

And last we remove the temporary files.

This is useful if your doing a script that requires you to move around a lot of text from one file to another and back, as this example:

#!/bin/bash

sed 's/www/ftp/g' tmp > .tmp.$$
sed 's/com/org/g' .tmp.$$ > .tmp2.$$
sed 's/ /_/g' .tmp2.$$ > .tmp3.$$
mv -f .tmp3.$$ tmp
rm -f .tmp.$$ .tmp2.$$ .tmp3.$$

exit 0

Here we change all www's in a file (tmp) to ftp, then we change all com's to org, and then all spaces to underscores.
After that we move the fully changed file so it overwrites the original file.
Then removing the temporary files and exit the script.

If you have a good look at it, it's really easy.

Another nice trick is as I showed in the example prior to the last one:

...
one=`cat .tmp.$$`
two=`cat .tmp2.$$`
...

That a variable can hold a command can prove to be useful, like this:

#!/bin/bash
time=`date +%H:%M:%S`

echo "$time" >> log
echo "some input to the log" >> log
sleep 60
echo "$time" >> log
echo "some input to the log a minute later" >> log

exit 0

But, it can hold more than just a command, it can actually *hold* the contents of a whole file.
Say now that you made a script and have a pretty large readme file, and want to display that as a 'man page' to the script if the argument --help is used to execute the script, then you can do like this:

#!/bin/bash
one="$1"
help=`cat README`

if [ "$one" = "--help" ]; then
$help | more
...

Of course it would be easier to say:

#!/bin/bash
if [ "$?" = "--help" ]; then
more README
fi

But these examples are just here for illustration so you get the point of usage for commands and so.

Another trick is, if you wanna hide script/program you can rename it to: -bash, that way it will look as a normal bash running in the ps (process list): you rename it by doing:

mv script ./-bash

Then execute it like normal ./-bash

Yet another trick, is if you're doing a script where you want each line of a file as a variable, unlike for which takes each word as a variable. This can be done like this:

#!/bin/bash
file="$1"
min="0"
max=`cat $file | wc -l`

if [ "$1" = "" ]; then
echo "Usage: $0 <file>"
exit -1
fi

while [ "$min" != "$max" ]; do min=`expr $min + 1`
curline=`head -$min $file | tail -1`
echo $curline
test $min -eq $max && exit 0
done

The test is there to make sure that it will end when $min and $max are the same. Now this can be done with for if you change the 'IFS' (described later), but that is not recommended, especially if you export IFS since that would change the environment and hence screw with the system scripts if they were to be run before changing IFS back to normal, but enough about that now, just keep it somewhere far back in your head, don't change IFS unless you know what you're doing.

AL: Although this example is intended to show usage, it actually runs rather slowly, because for each line in the file, there is run cat, wc, head and tail. Better is something like sed -n -e <line number required>p filename, e.g.:

curline=`sed -n -e ${min}p $file`

-n means suppress printing of pattern space (often used with p, explained below)
-e means execute the following script
${min}p is a script which means '<for this line number>, print'

This still runs through the file once for every line, but only uses sed.

If you don't understand this little script at this point, don't worry, you will understand it the second time you read this tutorial =)


Now let's take a quick look at arrays in shell scripting.

First off, an array is what it says, it's an array of something, now, to declare a variable that can hold an array we create it with the command 'declare', let's make a short example:

alien:~$ declare -a foo=(1 2 3 4 5)
alien:~$ echo ${foo[0]}
1
alien:~$ echo ${foo[1]}
2
alien:~$ foo[1]=bar
alien:~$ echo ${foo[1]}
bar
alien:~$

First of all, to understand the declare command better do "help declare" at a console and it'll display this:

declare: declare [-afFrxi] [-p] name[=value] ...
    Declare variables and/or give them attributes.  If no NAMEs are
    given, then display the values of variables instead.  The -p option
    will display the attributes and values of each NAME.

    The flags are:

      -a        to make NAMEs arrays (if supported)
      -f        to select from among function names only
      -F        to display function names without definitions
      -r        to make NAMEs readonly
      -x        to make NAMEs export
      -i        to make NAMEs have the `integer' attribute set

    Variables with the integer attribute have arithmetic evaluation (see
    `let') done when the variable is assigned to.

    When displaying values of variables, -f displays a function's name
    and definition.  The -F option restricts the display to function
    name only.

    Using `+' instead of `-' turns off the given attribute instead.  When
    used in a function, makes NAMEs local, as with the `local' command.

So here we see that the -a switch to declare makes the variable an array.
So after getting that 'declare -a' we declare the variable as an array, with the array within parentheses.

And then to make use of it, we use the way to write a variable like this:
${variable name here[number]}
and the number inside the []'s is the number that points to which part of the array it should use, beginning from 0 which is the first.

Let's make another short example:

declare -a foo=(this is another example)
echo "The array (${foo[*]}) has (${foo[0]}) as first, and (${foo[3]}) as last."

The output of this would be:

The array (this is another example) has (this) as first, and (example) as last.

Now, this isn't something you'll use in every day scripting, but it's still something you should know the existence of, just in case you see it or need it at some point.


Now here's a less common way of using bash, CGI scripts.
Most people don't associate shell scripting with cgi, but it works just as well as any other language, so here I'd like to show you how to make CGI scripts in bash.


Here is the first example which is a simple cgi counter in bash.
A note is that all CGI scripts should be in the servers cgi-bin directory or any subdirectory there off, unless the server is configured to see any other directories as cgi directories.

#!/bin/bash

test -f date.txt || echo `date "+%B %d %Y"` > date.txt
test -f counter.txt || echo '0' > counter.txt
current=`cat counter.txt`
date=`cat date.txt`
visitor=`expr $current + 1`

echo "$visitor" > counter.txt
echo 'Content-type: text/html'
echo ''
echo '<br>Vitor:'
echo '<br>'$visitor'<br>Since'
echo '<br>'$date'</br>'

Let's take this one line by line here:
First the shell ....

#!/bin/bash

Then we test if there is a file called date.txt, if not then we echo the current date to it and hence creating it.

test -f date.txt || echo `date "+%B %d %Y"` > date.txt

Then we test if there is a file called counter.txt and if not we echo a 0 to it and so create that one too.

test -f counter.txt || echo '0' > counter.txt

Now we declare the variables, current is the contents of counter.txt.

current=`cat counter.txt`

The date variable is the contents of date.txt.

date=`cat date.txt`

And visitor is the sum of the contents of counter.txt + 1.

visitor=`expr $current + 1`

And then we echo the new increased number to counter.txt.

echo "$visitor" > counter.txt

And here comes the HTML part. the first top line is the 'cgi header': that should ALWAYS be there:

echo 'Content-type: text/html'
echo ''

Then we move on to the *real* html:

echo '<br>Vitor:'
echo '<br>'$visitor'<br>Since'
echo '<br>'$date'</br>'

The <br> is a linebreak in html
The bash variables have to be *outside* the 's else they will simply show up as $visitor or $date literally, that's why it's made like this:

echo 'text' $variable 'some more text'

So that the text is enclosed with 's, but the variables are between or rather outside of them.
Anyway, this cgi will create a section that looks like this on a webpage:

   Vitor:
     1
   Since
May 29 2001

To add that to a html code you add this tag to your html/shtml page:

<!--#exec cgi="<path to counter>" -->

With the path to the counter it could look like this:

<!--#exec cgi="/cgi-bin/counter/counter.cgi" -->

Not so hard is it?


Here is another example of a CGI script in bash (actually the second CGI script I ever made).

#!/bin/bash

method=`echo $QUERY_STRING | awk -F'=' '{print $1}'`
host=`echo $QUERY_STRING | awk -F'=' '{print $2}'`

if [ "$method" = "nslookup" ]; then
echo 'Content-type: text/html'
echo ''
echo '<html>'
echo '<body bgcolor="white">'
echo '<center>'
echo '<br>nslookup '$host' (This might take a second)<br>'
echo '<hr width="100%">'
echo '</center>'
echo '<pre>'
nslookup $host
echo '</pre>'
echo '<center>'
echo '<hr width="100%">'
echo '<br>nslookup compleat'
echo '</center>'
echo '</body>'
echo '</html>'
fi

if [ "$method" = "ping" ]; then
echo 'Content-type: text/html'
echo ''
echo '<html>'
echo '<body bgcolor="white">'
echo '<center>'
echo '<br>ping '$host' (This might take a second)<br>'
echo '<hr width="100%">'
echo '</center>'
echo '<pre>'
ping -c 5 $host
echo '</pre>'
echo '<center>'
echo '<hr width="100%">'
echo '<br>ping compleat'
echo '</center>'
echo '</body>'
echo '</html>'
fi

if [ "$method" = "scan" ]; then
echo 'Content-type: text/html'
echo ''
echo '<html>'
echo '<body bgcolor="white">'
echo '<center>'
echo '<br>Scanning host '$host' (This might take a minute)<br>'
echo '<hr width="100%">'
echo '</center>'
echo '<pre>'
nmap $host
echo '</pre>'
echo '<center>'
echo '<hr width="100%">'
echo '<br>Scan compleat'
echo '</center>'
echo '</body>'
echo '</html>'
fi

Now let's take a look at what that means:


This time it wont be all the lines, but all the new parts:

First the 2 variables:

method=`echo $QUERY_STRING | awk -F'=' '{print $1}'`
host=`echo $QUERY_STRING | awk -F'=' '{print $2}'`

These are made this way because of how the CGI script imports the variables from a form (I'll come back to this), the $QUERY_STRING variable is from the webservers environment, and so is one of the httpds env variables.

And what you do with the $QUERY_STRING is depending on how you create your web form .... but as I said I'll get back to that.

Now the rest:

if [ "$method" = "nslookup" ]; then

That was pretty obvious .... if the first field of $QUERY_STRING (separated by a =, is nslookup, then go ahead here:

echo 'Content-type: text/html'
echo ''

Yes the header ....

echo '<html>'
echo '<body bgcolor="white">'
echo '<center>'
echo '<br>nslookup '$host' (This might take a second)<br>'
echo '<hr width="100%">'
echo '</center>'
echo '<pre>'

Create a HTML page ... and then after the <pre> we do the actual center part of the script:

nslookup $host

Which will resolve the DNS of the host (try the command and see), And after that we end the html page:

echo '</pre>'
echo '<center>'
echo '<hr width="100%">'
echo '<br>nslookup compleat'
echo '</center>'
echo '</body>'
echo '</html>'

and then end the if statement:

fi

and then the same for the others, just different objects at what they should do, as this was nslookup, the other sections will mnap (portscan) and ping the host instead.

Now how would a full HTML page look to make use of this cgi script?
As we this time need input to get the host or IP to scan/ping/nmap.

Well like this:

<html>
<body bgcolor="white">
<center>
<p><font size="+1">Enter host or IP</font></p>
<hr width="100%">
<br>
<form action="http://www.yourdomain.com/cgi-bin/scan.cgi" method="get">
<input type="text" name="scan" value="" size="30">
<input type="submit" value="portscan">
</form>
<p>
<form action="http://www.yourdomain.com/cgi-bin/scan.cgi" method="get">
<input type="text" name="nslookup" value="" size="30">
<input type="submit" value="nslookup">
</form>
<p>
<form action="http://www.yourdomain.com/cgi-bin/scan.cgi" method="get">
<input type="text" name="ping" value="" size="30">
<input type="submit" value="ping -c 5">
</form>
</center>
</body>
</html>

Now what does all this mean ? ....

Well, I won't turn this into a HTML tutorial, but I'll explain this so you can make use of bash for CGI.

Right to the important HTML part here:

<form action="http://www.yourdomain.com/cgi-bin/scan.cgi" method="get">
<input type="text" name="scan" value="" size="30">
<input type="submit" value="portscan">
</form>

Here we create a form, as in an input field, which will add it's input (in a specific way) to the end of the url in action="".
The method is get since we're getting the output of the cgi script.
We name this field scan so we get the output this way:

scan=<input>
Where the <input> is what you typed in the input box.
And then we make an "ok" button that says "portscan".
So if you type say 127.0.0.1 and press the portscan button the URL it will be directed to is this:
http://www.yourdomain.com/cgi-bin/scan.cgi?scan=127.0.0.1

And this "scan=127.0.0.1" will be the $QUERY_STRING environmental variable.

And so the script is starting to make sense.


Here's a REALLY simple cgi script just for the illustration as well.

#!/bin/bash

string="Hello World"

echo 'Content-type: text/html'
echo ''
echo '<html>'
echo '<br>'$string'</br>'
echo '</html>'

And the html to call that ..... just a normal hyper link.

<a href="http://www.yourdomain.com/cgi-bin/yourscript.cgi">Link</a>

And that's it.


That's it on the tricks, now let's move on to practical examples so you get a little bit of feel for how you can use bash to make things easier for you.

===============================================================================

5 - Practical Scripting Examples.

============================================================= Table Of Contents

I'd first like to add a note which you already probably know: "./" means look in current directory instead of the "PATH".

To give that an example, say now that you have a script in your home directory called ls or dir, how would you execute that without getting the contents of the directory? Well, that's why you use "./" before a name to execute it if it's in the current directory.

"../" is the previous directory (one directory further up towards "/" than you are currently in), this can be used as this, say that you have a script called "script" in "/home/user/" and you are standing in "/home/user/nice/" and you don't want to leave the directory but still want to execute the script.

Then you do, "../script" and if you are in "/home/user/nice/blah/" you would do, "../../script". "../../" means 2 directories back. Get the idea?

Anyway, now to the practical examples, which are working scripts for various purposes, to give an idea about what you can do with shell scripting. New things previously not explained will show up in this section, but I will explain them as we go along.

Let's start with simple examples and move on to harder parts. As for first I'll stick to useless scripts =) just for illustration. Explanation on the scripts follow after them, as usual. So here we go on that.

#!/bin/bash

one="$1"
something="$2"

if [ "$one" = "" ]; then
echo "Usage: $0 [name] <anything goes here>"
exit 0
fi

function first {
clear
echo "this is a test script !"
echo
echo "name followed on $0 was - $one - "
echo
echo "if you typed anything after the name it was: $something"
echo
}

first

exit 0

Executed without any thing after the script name it looks like this:

alien:~$ ./script
Usage: ./script [name] <anything goes here>
alien:~$

Executed with a name it looks like this:

alien:~$ ./script Jerry
----------<on a cleared screen>----------
this is a test script !

name followed on ./script was - Jerry -

if you typed anything after the name it was:

alien:~$

Executed with a name and something else it looks like this:

alien:~$ ./script Jerry homer
----------<on a cleared screen>----------
this is a test script !

name followed on ./script was - Jerry -

if you typed anything after the name it was: homer

alien:~$
Notes:
$0 is the script name's variable so you can do a "Usage: <scriptname>" regardless of whether the script is renamed after you made it.
$1 is the first thing that's typed after the script in the command line.
$2 is the second thing that's typed after the script in the command line.
$3, $4 and soon .....
one="$1" this puts the contents of "$1" into the variable $one which can be very useful to avoid errors.
clear clears the screen.

This next example is a script which you really shouldn't use... It's here as an example for a working help script, but *could* cause harm if not used correctly.

So if you loose anything because of using it, it's all on you. and don't say I didn't warn you.

#!/bin/bash

if whoami | grep -v root >> /dev/null; then
    echo "you have to be root to use this"
 exit 1
else

cat /etc/passwd | cut -f1 -d : | grep -v halt | grep -v operator | \
        grep -v root | grep -v shutdown | grep -v sync | grep -v bin | \
        grep -v ftp | grep -v daemon | grep -v adm | grep -v lp | \
        grep -v mail | grep -v postmaster | grep -v news  | grep -v uucp | \
        grep -v man | grep -v games | grep -v guest | grep -v nobody > user.list
fi

for USER in `cat user.list`; do
 if cat /home/$USER/.bash_history | grep passwd >> /dev/null; then
    echo
    echo "user $USER have tried to access the passwd file"
    echo "do you want to remove $USER from your system [y/n] "
read YN
 if [ "$YN" = "y" ]; then
    echo "user $USER is being deleted"
    echo "home dir of user $USER is however intact"
    echo
    remuser $USER
 else
    echo "user $USER is not deleted"
    echo
 fi
else
    echo "$USER haven't tried to access the passwd file"
 fi
done

 rm user.list
    echo
    echo "Script finished"
    echo
exit 0

I will just translate this script into real/clear English:

if (check own user-name) is anything else but root >> send output to a black hole
say, "you have to be root to use this"
terminate program.
in other cases (in this case that can only be if the user is root)

list the contents of the file "/etc/passwd" combined with - cut out the user names (field 1 separated by ":") grep everything except lines containing the following words/names: halt operator root shutdown sync bin ftp daemon adm lp mail postmaster news uucp man games guest nobody and send it to the file "user.list"
end "if" statement

for each user in the "user.list" file do the following
if the word "passwd" is present in "/home/$USER/.bash_history" >> output to
the system's black hole
say nothing
say "user $USER has tried to access the passwd file"
say "do you want to remove $USER from your system [y/n]"
read if the input from the keyboard is a "y" or "n"

if the variable for the answer of the input is "y" then
say "user $USER is being deleted"
say "home dir of user $USER is however intact"
say nothing
removing the user from the system that tried to access the passwd file
in other cases
say "user $USER is not deleted"
say nothing
end "if" statement
in other cases
say $USER haven't tried to access the passwd file
end "if" statement
exit the for-loop

remove the "user.list" file
say nothing
say "Script finished"
say nothing

exit and return to the shell command line.

Note: grep -v means show every line which does *not* contain the string after the -v.


Here is another way of doing the exact same script, just to illustrate that the same thing can be done in several different ways:

#!/bin/bash

if [ "$UID" != "0" ]; then
    echo "you have to be root to use this"
    exit -1
fi

for uids in `cat /etc/passwd`; do
    useruid=`echo "$uids" | awk -F':' '{print $(3)}'`
    test "$useruid" -ge "500" 2>/dev/null &&
    echo "$uids" | awk -F':' '{print $(1)}' > user.list
done

for USER in `cat user.list`; do
    if (grep passwd /home/$USER/.bash_history >/dev/null); then
       echo
       echo "user $USER have tried to access the passwd file"
       echo "do you want to remove $USER from your system [y/n] "
       read YN

       case $YN in
            y* | Y*)
               echo "user $USER is being deleted"
               echo "home dir of user $USER is however intact"
               remuser $USER
               echo
               ;;
            n* | N*)
               echo "user $USER is not deleted"
               echo
               ;;
       esac
    else
       echo "$USER haven't tried to access the passwd file"
       rm -f user.list
       echo
       echo "Script finished"
       echo
    fi
done

exit 0

Since this script does the exact same thing, but in another way, I'll leave you with the experience of trying to figure out the differences and how it works with the help of this tutorial, you might not get this right until you've read this tutorial twice.

A tip is: try to make a comment to each line with what it does and why.


This below script is a "Wingate" scanner, to scan for wingates that can be used to bounce off and such things, don't know if that's really legal so take that on your own risk.

Anyway here comes the script:

#!/bin/bash
echo > .log.tmp
echo > .log2.tmp
echo "sleep 7" > wg.config
echo "killall -2 telnet" >> wg.config

scan="$1"
count="0"
max="255"

clear

if whoami | grep root >> /dev/null ; then
   echo "please use this as user and not root, since it would kill all users"
   echo "telnet sessions"
 else
clear
fi

if [ "$1" = "" ]; then
        echo " usage is: $0 <C host> "
        echo "  examples:"
        echo "  $0 127.0.0"
        echo " That will scan from 127.0.0.0 to 127.0.0.255"
        echo
        echo "be aware though, while it scans it also kills any other telnet"
        echo "sessions you might have ...."
 exit 0
fi

while [ "$count" != "$max" ]; do count=`expr $count + 1`
        echo "Attempting connection to $1.$count "
        echo > .log2.tmp
        ./wg.config &
        telnet $scan.$count >> .log.tmp
        cat .log.tmp | grep -v refused | grep -v closed | grep -v Connected | grep -v Escape | grep -v login >> .log2.tmp
        echo >> .log.tmp
    done
  echo "Script Finished, results stored in .log.tmp and .log2.tmp"
exit 0

This time I will not translate the script into clear English and I will not show how it looks executed, I leave that for you to do =)


Now a final practical example of a script, this is a small graphical front end to the console mp3 player mpg123 so you got to have that to work and you need to execute this script in a directly where you have mp3's ....

Also if you want the X-windows part of it to work you need to get and install Xdialog, you can get that from www.freshmeat.net ...

However if you have Linux Mandrake you should be good anyway, Xdialog comes as default in Mandrake.

This script should be named xmpg123. So here we go:

#!/bin/bash
dialog --backtitle "xmpg123" \
       --title "Main menu" \
       --menu "Make your choice" 13 60 6 \
        1 "X-windows" \
        2 "Ncurses" \
        3 "Exit" 2> .tempfile
        output=`cat .tempfile`
        echo $output
        rm -f .tempfile

if [ "$output" = "1" ]; then
for songs in `ls -1 *.mp3`; do
echo "$songs mp3-file" >> .tempfile
done
output=`cat .tempfile`
Xdialog --menu 2 2 2 1 $output  \
        2> .tempfile
        output=`cat .tempfile`
        mpg123 $output
        rm -f .tempfile
fi

if [ "$output" = "2" ]; then
for songs in `ls -1 *.mp3`; do
echo "$songs mp3-file" >> .tempfile
done
menu=`cat .tempfile`
dialog --menu "Make your choice" 13 70 6 $menu 2> .tempfile
       output=`cat .tempfile`
       mpg123 $output
       rm -f .tempfile
fi

exit 0

A note being that dialog and Xdialog seems to be in early stages, so this may look sort of buggy if you don't have the great dialog god at your side...


And don't forget to "chmod u+x <script name>" or "chmod a+x <script name>" to make your scripts executable.

===============================================================================

6 - Customize your system and shell.

============================================================= Table Of Contents

This section is dedicated to how you can customize your system in various ways, this section was never planned to be in this tutorial, but since I have received so many questions on how to do all this, I might as well include it in the tutorial.


First of I'm going to explain the local settings, this means the settings that will only affect a single user and not the whole 'global' system. And the most logical way to start this is (I think) to talk about the shell.


At the very top of this tutorial you will find the various types of shells, default for most systems is /bin/bash, this is set in the /etc/passwd file so a normal user can not change that.

What a normal user can do if he wants to use another shell is to start it from his ~/.bashrc file.

So say now that you feel the urge to run tcsh, then just add the line /bin/tcsh in your ~/.bashrc, this may be done by doing:

echo "/bin/tcsh" >> ~/.bashrc

personally I prefer the standard bash.

But if you do have root (super user) access to the system, you can change the shell type correctly in the /etc/passwd file.

here's a user account with /bin/bash from /etc/passwd.

User:x:500:500:my real name:/home/user:/bin/bash

And here the same line changed to /bin/tcsh (tenex C shell)

User:x:500:500:my real name:/home/user:/bin/tcsh

Here are the system variables you can use to change your environment, these can be set and exported from your ~/.bash_profile or /etc/profile. It's not all of the variables but all the really interesting ones, so here we go:

BASH=
this can also set your shell type, it's most commonly defaulted to BASH=/bin/bash
BASH_VERSION=
this can change the version reply of bash, on my system this is defaulted to BASH_VERSION='2.03.19(1)-release'
ENV=
this should point to a file containing your environment, this is by default: ENV=~/.bashrc
HISTFILE=
this should point to a file that will contain your shell 'history', as in your previously used commands. this is by default set to: HISTFILE=~/.bash_history
HISTFILESIZE=
the max allowed size of the history file, usually around 1000
HISTSIZE=
about the same as HISTFILESIZE
HOME=
this should point to your home dir
HOSTNAME=
this is your hostname
HOSTTYPE=
this should return the same as the `arch` command.
IFS=
'Internal Field Separator' .... this is a delimiter, often defaulted to a new line as this:
......
IFS='
'
......
INPUTRC=
defaulted to INPUTRC=/etc/inputrc
LANG=
language variable, default is en for English
LANGUAGE=
about the same as LANG, also defaulted to en for English
LINGUAS=
defaulted to en_US:en also a language variable.
LS_COLORS=
sets colors to the ls command. This on my system is defaulted to this:
......
LS_COLORS='no=00:fi=00:di=01;34:ln=01;36:pi=40;33:so=01;35:bd=40;33;01:\
cd=40;33;01:or=01;05;37;41:mi=01;05;37;41:ex=01;32:*.cmd=01;32:*.exe=01;32:\
*.com=01;32:*.btm=01;32:*.bat=01;32:*.tar=01;31:*.tgz=01;31:*.tbz2=01;31:\
*.arc=01;31:*.arj=01;31:*.taz=01;31:*.lzh=01;31:*.lha=01;31:*.zip=01;31:\
*.z=01;31:*.Z=01;31:*.gz=01;31:*.bz2=01;31:*.bz=01;31:*.tz=01;31:*.rpm=01;31:\
*.jpg=01;35:*.jpeg=01;35:*.gif=01;35:*.bmp=01;35:*.xbm=01;35:*.xpm=01;35:\
*.png=01;35:*.tif=01;35:*.tiff=01;35:'
......
So just add what you want here, and colors are the same as explained about how to set the prompt later down, but without the [ in front and m on the end.
MAIL=
mail file, usually MAIL=/var/spool/mail/<username>
OSTYPE=
This can change your OS reply, it's on a linux defaulted to: OSTYPE=linux-gnu
PATH=
changes your path, this variable is explained in the explanation of the /etc/profile file
PPID=
parent pid .... this is a read-only variable ... so you can't change it.
PS1=
the prompt variable, explained later down.
PS2=
the *more to come* variable, as if you type an unfinished command string, it will bring you a new prompt where you can finish it, this is usually defaulted to: PS2='> '
SHELL=
another way to change your shell type ...
TERM=
terminal type, usually defaulted to: TERM=linux but can also be like: TERM=vt100 there are more video terminals than 100 though.
UID=
your user ID, if you're root this will be 0, this is a readonly variable.
USER=
your user name ....
USERNAME=
same as $USER

Say that you want to change your shell to /bin/csh and your path to just /bin (you don't), but just if you would in your: .bash_profile add:

SHELL=/bin/csh
PATH=/bin

export PATH SHELL

Not so hard huh ?


The next thing here is a question that I've heard a lot, and that is "how do I change my command prompt?".

The command Prompts variable is named PS1 ($PS1). For a prompt that looks like this:

[alien@localhost alien]$

the contents of the PS1 variable would be this:

[\u@\h \W]\$

All the prompt's internal variables start with a \ (backslash).

Useful:

\$ = the prompt ($ for user and # for root)
\d = date
\h = abbreviated hostname (root.host.com would become root)
\H = full hostname
\s = shell type
\t = time
\T = time with seconds
\u = username
\v = shell version (short)
\V = shell version (long)
\w = full path
\W = current directory name

less useful:

\e = erase rest of line .... not very useful
\n = new line ... not very useful
\r = whatever comes after \r is displayed before the first character.

A couple of examples would be:

*BSD like.

PS1="\u: \w> "

DOS like.

PS1="C:\w > "

RedHat like.

PS1="[\u@\h \W]\$ "

Init 1 like.

PS1="\s-\v \$ "

How do I use colors in the prompt ?

To use colors in the prompt you need to be familiar with the escape sequence color codings, those are as follows:

reset         = ^[[0m
flashing      = ^[[5m
black         = ^[[0;30m
red           = ^[[0;31m
green         = ^[[0;32m
yellow        = ^[[0;33m
blue          = ^[[0;34m
magenta       = ^[[0;35m
cyan          = ^[[0;36m
white         = ^[[0;37m
highblack     = ^[[1;30m
highred       = ^[[1;31m
highgreen     = ^[[1;32m
highyellow    = ^[[1;33m
highblue      = ^[[1;34m
highmagenta   = ^[[1;35m
highcyan      = ^[[1;36m
highwhite     = ^[[1;37m
bg-white      = ^[[47m
bg-magenta    = ^[[45m
bg-blue       = ^[[44m
bg-red        = ^[[41m
bg-black      = ^[[40m
bg-green      = ^[[42m
bg-yellow     = ^[[43m
bg-cyan       = ^[[46m

Important to know is that the leading "^[" is NOT 2 characters, it's ONE control character that shows up as 2 characters when you edit the file, or is described by 2 characters. When editing, if you have a real ^[ and you try to delete the [ it will delete both the [ and the ^ at the same time.


Not really sure where to put this note but here,

^[[<number>G

Puts the cursor at column <number>, as this:

echo -n "Starting myprog:" && echo -e "^[[50G OK" || echo -e "^[[50G FAILD"

So how do you get a real control character?

Either you use the very old line editor ed and press Ctrl+[ to get the control character (ed commands are described at the end of this tutorial), or you can use emacs or the text editor joe.

To get control characters in emacsyou press ^Q and ^<what you want>, as if you want a ^[ you press ^Q^3, and then ^X^S^X^C to save and quit.

To get control characters in joe you press ` and then the character to make a control character, in this case [; when you do this in joe the ^[ should like like a bold [.

To save and quit in joe you press: Ctrl+K followed by Ctrl+X

It's only the ^[ that is a control character: the rest is normal ['s and numbers and so on.

Don't forget to enclose all your colors codes in \[ \]; this means that ^[[0;31m (red) would be written as \[^[[0;31m\].

Where do I write this and how does an example look?

You add this in your ~/.bash_profile, you can put it at the end of the file.

Some examples are:

[ highblue-user red-@ highblue-host green-dir ] highblue-$
PS1="\[^[[1;34m\u^[[0;31m@^[[1;34m\h ^[[0;32m\W^[[0m\]^[[1;34m\$ \[^[[0m\] "

highblue-user highwhite-: highblue-path >
PS1="\[^[[1;34m\]\u\[^[[1;37m\]: \[^[[0;31m\]\w \[^[[0m\]> "

(you can not cut and paste these examples without editing the ^['s to real control characters, and know that a color prompt is almost always buggy)


The next thing to take up is how to set aliases and to change system variables.

An alias is set in the ~/.bashrc file if you use /bin/bash else, it's most likely in your .'shell type'rc, e.g. as .zshrc, .csh, .tcsh, etc.

An alias means that you can make a short command for a longer command, as the alias "l" can mean "ls" and the alias "la" can mean "ls -la', and so on. An alias is written like this (also a list of useful aliases):

alias rm='rm -i'
alias mv='mv -i'
alias cp='cp -i'
alias s='cd ..'
alias d='ls'
alias p='cd -'
alias ll='ls -laF --color'
alias lsrpm='rpm -qlp'
alias lstgz='tar -tzf'
alias lstar='tar -tf'
alias mktgz='tar -cfz'
alias untar='tar -vxf'
alias untgz='tar -vzxf'

These are:
rm will now ask before removing anything.
mv will now ask before overwriting anything.
cp will now ask before overwriting anything.
s will now work as cd ..
d will now work as ls
p will now work as cd - (takes you to your last dir. I.e. you are in /usr/local/bin/ and move away by doing a cd /, if you from here wanna go back to /usr/local/bin/ you simply type cd -, or now just p.)
ll will do a ls -la with colors and a * after executable files and a / after directories.
lsrpm will list the contents (where the files will end up if you install it) of any .rpm file.
lstgz will list the contents of a .tar.gz or .tgz file.
lstar will list the contents of a plain .tar file.
mkgz will make a tgz archive (mktar archive.tgz directory).
untar will untar a .tar file.
untgz will unzip and untar a .tar.gz or a .tgz file.

There is more alias like things you can set in the ~/.bashrc file, like smaller functions that works as aliases, like this:

function whichrpm { rpm -qf `'which' $1`; }

Typing whichrpm <command> at a prompt will name the rpm file it came with.

The rpm -qf command works like this:

alien:~$ rpm -qf /usr/bin/dir
fileutils-4.0i-1mdk
alien:~$

And the function works like this:

alien:~$ whichrpm dir
fileutils-4.0i-1mdk
alien:~$

function - tells bash that it's function.
whichrpm - user defined name of the function.
{ and } - starts and ends the function.
rpm -qf – command
` command quote
' precise quote
which - command to locate a file in your path
$1 - first argument after the function (the command after the function name when you execute it).
; - end line
function whichrpm { rpm -qf `'which' $1`; }

So when you execute this, the system will think: Aaah, a function within those {}'s, which I should call for when I see the word whichrpm, and what's after that word ($1) will be used as argument to which, and what that returns will be used after rpm -qf, which works like this:

alien:~$ which dir
/usr/bin/dir
alien:~$

So `'which' $1` (when executed with the word dir) returns /usr/bin/dir, and so the whole function will finally execute: rpm -qf /usr/bin/dir


Now more about the files in /etc, here you can't be user anymore; to edit the files in /etc requires you to be root.

First here I'm going to talk about the /etc/crontab configuration file.

The /etc/crontab is the global system file for cron jobs. cron is short for chronological, and as the name tells it's doing things in a chronological order, as you can tell it to run a script or a program once every 1 minute, or you can tell it to run something annually, and anything in between.

On RedHat like systems you have the dirs:

/etc/cron.daily/
/etc/cron.hourly/
/etc/cron.monthly/
/etc/cron.weekly/

Any script or program that lives in those files will execute by the last name of the file, as if you put a script in /etc/cron.weekly/, the script will execute weekly.

The /etc/crontab file looks like this:

SHELL=/bin/bash
PATH=/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=root
HOME=/

# run-parts
01 * * * * root run-parts /etc/cron.hourly
02 4 * * * root run-parts /etc/cron.daily
22 4 * * 0 root run-parts /etc/cron.weekly
42 4 1 * * root run-parts /etc/cron.monthly

The SHELL determines what shell that should be used to execute the things in the crontab.

The PATH determines what directory's it should look in for commands or programs if no other specific path is given to a program, command or script.

The MAILTO variable determines to what user cron should send mails to on errors.

And the HOME variable determines cron's root/home/base directory.

The first 5 fields determines when to run a job, here's what they mean:

Field 1: minutes (0-59)
Field 2: hours (0-23)
Field 3: day of month (1-31)
Field 4: month (1-12 - or names)
Field 5: weekday (0-7 - 0 or 7 is Sun, or use names)

The next field is the user that owns the execution process.

Then we have run-parts, and after that the file to execute. (if the file to execute is a dir, it will execute everything in it)

To use the crontab as a user (root included) simply type: crontab -e This brings you to a VI like editor (see VI commands later in this tutorial). Say now that you have a script /home/user/check.sh that you wanna run every 5'th minute. then you type crontab -e. Press the 'Esc' key, followed by o to get to "insert" or "edit" mode. In there make the following line:

0,5,10,15,20,25,30,35,40,45,50,55 * * * *       /home/user/check.sh --flag

Then press 'Esc' followed by : and then type wq followed by enter to write/save and, quit the file, and that's it.

When you run crontab as user you don't have to specify what user that should own the process, "* * * * * file" should be enough.

Another way of writing:

0,5,10,15,20,25,30,35,40,45,50,55 * * * *       /home/user/check.sh --flag

Is this:

0-59/5 * * * *       /home/user/check.sh --flag

That means do this (/home/user/check.sh --flag) from 0-59 with 5 as an interval. This means that:

* 0-23/2 * * *       /home/user/check.sh --flag

Would run the same script every other hour.

Not very hard is it ?


Then we have the /etc/fstab file which is a list of the HD partitions the system should mount as what when the system boots. This may look like this:

/dev/hda1               /                       ext2    defaults        1 1
/dev/hda3               none                    swap    sw              0 0
/dev/hda4               /home                   ext2    defaults        1 2
/dev/hda6               /tmp                    ext2    defaults        1 2
/dev/hdc1               /windows                vfat    defaults        0 0
/dev/fd0                /mnt/floppy             auto    noauto,nosuid   0 0
/dev/hdb                /mnt/cdrom              auto    noauto,ro       0 0

First it's the HD partition, then (a few tabs in) the mount point (where the eventual contents of the HD partition should end up), then what file system the partition has, further is if it should be mounted by default etc. and the last 2 numbers is fs_freq and fs_passno (see the man page for fstab).

The possible HD partitions you have to find for your self or know... a tip is to go over the HD's with fdisk, and check for free space.

The possible mount points is only limited by your imagination, though there must always be a /. A good disk usage should have these partitions:

/       5%
/usr    30%
/home   30%
/tmp    10%

And 25% over for other partitions, like /sources, or whatever.

The possible and supported file systems are currently:
minix, ext, ext2, xiafs, msdos, hpfs, iso9660, nfs, swap, vfat, and perhaps ntfs.

The possible mount options are:
sync, user, noauto, nosuid, nodev, unhide, user, noauto, nosuid, exec, nodev, ro etc.
see the man mount page.

So say that you are going to add another cdrom that you want user to be able to mount, and the cdrom is on /dev/hdd, then the line to add would look like this (make sure you have the mount point dir, like here you have to mkdir /cdrom):

/dev/hdd                /cdrom                  auto    noauto,user,ro  0 0

And that's about it for the /etc/fstab


Now I'd like to explain one of the very important files, the /etc/profile file. In this file is the Global profile settings, that will apply for all users.

First in this file we should have the PATH variable. The directories in the PATH are the directories the system will look in if you type a command, for that command to execute it.

Say now that your path looks like this:

PATH="$PATH:/usr/X11R6/bin:/bin"

And you type ls, then the system will first look in /usr/X11R6/bin if it can find any file named ls, and if it doesn't find it there, it will look in /bin, and if it finds it there it will execute it.

The most common places on a system to store commands and programs is in these directories:

/usr/X11R6/bin
/bin
/sbin
/usr/bin
/usr/sbin
/usr/local/bin
/usr/local/sbin

A path with all those directories in it would look like this:

PATH="$PATH:/usr/X11R6/bin:/bin:/sbin:/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin"

The next thing in there can/should be the PS1 (the prompt), I've already taken up how to customize the prompt, so no need to do that again.

Then (at least in RedHat like systems) we have this:

[ "$UID" = "0" ] && {
ulimit -c 1000000
                } || {
ulimit -c 0
}

This says: if the UID of the user is 0 (root) then do: ulimit -c 1000000 or if that doesn't work, do: ulimit -c 0.

Then we have an if statement about umask on the user...

After that we define some system variables, where after we export them.

Then we load all the .sh scripts in /etc/profile.d/

And that's it, in that file.

This is an important file if you wanna add any system variables, or if you want to change anything globally for the whole system.


Now on to the /etc/hosts.allow and /etc/hosts.deny files.

Those hosts who are in hosts.allow are always allowed to connect to the system under the condition that they have valid login and password of course.

Those hosts who are in hosts.deny can never establish a lasting connection to your system, even if they have a valid login and password.

If you don't want anyone to connect to your computer at all, you simply add the following to /etc/hosts.deny:

ALL: ALL
And this to /etc/hosts.allow:
ALL: LOCAL
Or if you have a network, you may wanna add this in /etc/hosts.allow:
ALL: LOCAL, 192.168.1.

Where 192.168.1. is your network call C network.

/etc/hosts.allow and /etc/hosts.deny understands the following wildcards:

ALL      The universal wildcard, always matches.
LOCAL    Matches any host whose name does not contain a dot character.
UNKNOWN  Matches any user whose name is unknown.
KNOWN    Matches any user whose name is known.
PARANOID Matches any host whose name does not match its address.

Read man hosts.allow or man hosts.deny (should be the same man file), to find out more about this.


Next up is the /etc/inputrc file, which contains brief keyboard configurations. If you want to something like Ctrl+W or something to a function of any kind here is the place to do that. The example from the file looks like this:

# Just a little example, how do you can configure your keyboard
# If you type Control-x s it's add a su -c " " around the command
# See the info files (readline) for more details.
#
# "\C-xs": "\C-e\"\C-asu -c \""

This would mean that if you want to add say: Ctrl+W to add the command time before another command you would do:

"\C-w": "\C-e\ \C-atime \

Another example would be, if you want to add: Ctrl+W Q to add: echo "<command>" around the <command> you would do:

"\C-wq": "\C-e\"\C-aecho \""

This means that if you type word and then press Ctrl+W followed by Q you will end up with: echo "word", pretty handy.

You can also add a .inputrc in your home dir with the same functions, but only for that user.

Just make sure you don't overwrite some other function, test the Ctrl+<key(s)> function that you wanna use so they don't already do something.

If you want to bind keys to functions or characters, this is not the place to do that, then you need to find your keymap like this one:

/usr/lib/kbd/keymaps/i386/qwerty/se-latin1.kmap.gz

gunzip it, edit it and then zip it up again.

I will not explain how to edit a keymap here, but it's not that hard, just read the contents of the unzipped keymap a few times and use the power of deduction.


The /etc/passwd holds the login information which looks something like this:

root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:
daemon:x:2:2:daemon:/sbin:
adm:x:3:4:adm:/var/adm:
lp:x:4:7:lp:/var/spool/lpd:
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
alien:x:500:500:Me:/home/alien:/bin/bash
user:x:501:501::/home/user:/bin/csh

You are looking on 7 accounts, namely: root, bin, daemon, adm, lp, shutdown, alien and user.

Each of the lines have 7 fields separated by ":". The fields from left to right are:

1 login-name
2 encrypted-password (this field contains only 'x' if there is an /etc/shadow)
3 uid (user id)
4 gid (group id)
5 user-information
6 home-directory
7 shell-type

If you make an account by hand in the /etc/passwd file, put a '*' in the encrypted-password field and use the passwd command to set the password.


The /etc/shadow file, if this file exists, this is where the real encrypted passwords are located, this file can only be read by the super-user (root), and it looks like this:

root:$1$UrbUdguK$yrO3U/dlwKC5K3y2ON/YM.:11056:0:21:7:::
bin:*:11056:0:99999:7:::
daemon:*:11056:0:99999:7:::
adm:*:11056:0:99999:7:::
lp:*:11056:0:99999:7:::
shutdown:$1$hu86lnLIhnklY8ijnHui7.nn/jYg/mU:11056:1:365:14:::
alien:$1$vf3tGCFF$YRoFUgFDR8CVK6hHOwU/p0:11056:0:50:14:31::
user:$1$asd8kiLY76JNdskDkj97kMiyBujy/jD:11074:2:100:14:3::

(I've changed the characters in the encrypted-password, so they are not valid)

The manual page (man 5 shadow) tells the following about the 9 fields:

Login name
Encrypted password
Days since Jan 1, 1970 that password was last changed
Days before password may be changed
Days after which password must be changed
Days before password is to expire that user is warned
Days after password expires that account is disabled
Days since Jan 1, 1970 that account is disabled
A reserved field

If anyone knows what the last field (after the final :) is reserved for ... please drop me a mail.

Read the lines from the files, and compare them with what the 9 fields mean, and see if you can make out how the accounts for each user is set up.


Now the /etc/motd,/tt> file.

The /etc/motd contains whatever you want to display to the user that logs into the system, this can be a set of rules for your system, or some ascii graphics or whatever you want.


And now the /etc/skel/ which is a dir and contains the basic files that will be given to any new user account.

Say that you add a file called, /etc/skel/.ircrc then all new useraccounts that are added will have a ~/.ircrc file in their home directory.


And last the /etc/issue and /etc/issue.net file.

On most systems there is only an /etc/issue file that works as both /etc/issue and /etc/issue.net, the issue file holds the information or rather text that is displayed to the user just before the login prompt, usually it is the system specifications, like operating system version and things like that.

The /etc/issue (if there is any /etc/issue.net) is the issue file for the local users, and the /etc/issue.net is for users that logs in from a remote host.


There is a lot more in the /etc directory, but what I've written this far is about what you need to customize your system to your needs.

===============================================================================

7 - Networking.

============================================================= Table Of Contents

Linux is known to be one of the best networking operating systems in the world, perhaps even THE best, unfortunately it's not the easiest OS to set up a good network in, but I hope that this section will make exclamation marks out of some question marks.


The first thing you need to do networking is 2 computers and network cards attached with a crossed network cable, or connected via a hub, with normal network cable (doh?).

The next step is to make sure the network cards work properly.

Make sure you have the networking support compiled into the kernel, you need to have the following checked in the kernel (example is from the Linux 2.2.14 kernel, using make menuconfig, you can read more about how you compile/recompile your kernel in /usr/doc/HOWTO/Kernel-HOWTO):

General setup  --->
        [*] Networking support
Networking options  --->
        [*] Kernel/User netlink socket
        [*] Network firewalls
        <*> Unix domain sockets
        [*] TCP/IP networking
        [*] IP: advanced router
        [*] IP: firewalling
        [*] IP: transparent proxy support
        [*] IP: masquerading
        [*] IP: ICMP masquerading
        [*] IP: aliasing support
        <*> IP: Reverse ARP
        [*] IP: Allow large windows (not recommended if <16Mb of memory)
Network device support  --->
        [*] Network device support
        Ethernet (10 or 100Mbit)  --->
                [*] Ethernet (10 or 100Mbit)
                (In here find your network card and check it.)
Filesystems  --->
        [*] /proc filesystem support

Then you add this line in your /etc/rc.d/rc.local

echo "1" > /proc/sys/net/ipv4/ip_forward () at boot time

If you have more then one network card, you may wanna add one as Module and one hard compiled (*) into the kernel, so that the kernel knows that it's 2 network cards.

Then you need to name them eth0 and eth1, this you *may* have to do even if you only have 1 network card, but it's not likely.

I have 2 network cards, one "3com 509 B" and one "3com 905" The first thing I need to do is to is to find the module name for the network cards.

Go to /lib/modules/2.2.14/misc/ and do an ls (the 2.2.14/ dir will be named after whatever kernel version you have: use uname -r to find out)

In there I found a file called 3c59x.o (that's the one I compiled as module), then I set that as eth0, like this: I open the file /etc/conf.modules (or /etc/modules.conf depending on the kernel and system) and add:

alias eth0 3c59x

Then I know the other card is a "3com 509 B" so I go to: /lib/modules/2.2.14/net/ and in there I find a 3c509.o, so I again add an alias in /etc/conf.modules:

alias eth1 3c509

Basically, you will find the network cards you added from the kernel in either /lib/modules/2.2.14/net/ or /lib/modules/2.2.14/misc/, or say now that you had a Linux 2.2.15 kernel then it would be: /lib/modules/2.2.15/net/ and /lib/modules/2.2.15/misc/

And remember to add the cardnames without the .o in the module name, as 3c509.o will be named 3c509 as an alias in /etc/conf.modules.


Now you wanna add the network card so it starts at boot time and get an IP. Now you must decide what network IP it should have (either 192.168.1.* or 10.0.0.* in this example I've used 10.0.0.*). Open or create a file called: /etc/sysconfig/network-scripts/ifcfg-eth0 (if it doesn't exist when you open it, it will be created.)

In this file type the following:

ONBOOT=yes
DEVICE=eth0
IPADDR=10.0.0.1
NETMASK=255.255.255.0
NETWORK=10.0.0.0
BROADCAST=10.255.255.255
BOOTPROTO=none

Then save and quit.

ifcfg-eth0 goes if this is your first network card, if it were your second network card on the same computer it would be ifcfg-eth1, and then the DEVICE variable assignment would say DEVICE=eth1.


After this you need to tell your computer what IP, network name and nick name it has. This you do in /etc/hosts. By default you should have this line in your /etc/hosts:

127.0.0.1       localhost       localhost.localdomain

Now you add your new hosts, the current computer and the other computer(s), here I have used the 10.0.0.* IP range.

10.0.0.1        main.bogus.com  main
10.0.0.2        sidekick.bogus.com      sidekick

Note that there is a TAB separating each of the 3 fields (IP hostname nick).


After that it's time to set up the forwarding and everything like that using ipchains. This you do by adding the following lines to your /etc/rc.d/rc.local

/sbin/ipchains -P forward DENY
/sbin/ipchains -A forward -i eth0 -j MASQ

You may also wanna execute the lines since /etc/rc.d/rc.local only loads at boot time.


At this time you may also wanna set up a caching nameserver on your system, both to speed up your surfing and to get your LAN (Local Area Network) to interact in a proper way.

In the following example I've used:

bind-8.2.2P5-1mdk.i586.rpm

and

caching-nameserver-6.0-3mdk.noarch.rpm
(A nameserver is depending on bind)

So after you installed bind and a caching nameserver this is what you wanna do, (everything in this example is based on the previously written network configurations):

First you need to edit a file named /etc/named.conf, where in you add a "zone". The zones in this example to add, looks like this:

zone "bogus.com" {
        type master;
        file "bogus.com";
};

zone "0.0.10.in-addr.arpa" {
        type master;
        file "10.0.0";
};

The first one is for the networked computers' hostnames, and the second for their IP's.

In this example I use 10.0.0.* as the network IP, but another common network IP is also 192.168.0.* .... those are the two most common/accepted ones.

Then you save and quit that, to go and create the files bogus.com and 10.0.0, which you do in: /var/named/

First we can create /var/named/bogus.com, and in there type the following:

@       IN      SOA     ns.bogus.com. main.bogus.com.  (
                                       2000020100 ; Serial
                                       28800      ; Refresh
                                       14400      ; Retry
                                       3600000    ; Expire
                                       86400 )    ; Minimum
               IN      NS      localhost.
      ;1       IN      PTR     localhost.
localhost       A       127.0.0.1
ns              A       10.0.0.1
sidekick        A       10.0.0.2
main            A       10.0.0.1
mail            A       10.0.0.1

(What comes before the Serial, 2000020100 is a date, 2000-02-01-00, so you can type that as your current date.)

Then you save and quit that, and create the file: /var/named/10.0.0, and in there you type this:

@       IN      SOA     ns.bogus.com. main.bogus.com.  (
                                      2000020100 ; Serial
                                      28800      ; Refresh
                                      14400      ; Retry
                                      3600000    ; Expire
                                      86400 )    ; Minimum
                NS      ns.bogus.com.
1               PTR     main.bogus.com.
2               PTR     sidekick.bogus.com.

Now it's almost time to start the nameserver, but first you wanna add the nameserver to your /etc/resolv.conf so you have any use of it.

Open /etc/resolv.conf and at the top of it add:

nameserver 10.0.0.1

and leave the rest of the file entries as they are if there are any, then save and quit that.

And now it's time to start the nameserver. To be sure that everything works normally, do these commands:

/usr/sbin/named
/usr/sbin/ndc restart

And then type 'nslookup', that should look like this:

root:~# nslookup
Default Server:  main.bogus.com
Address:  10.0.0.1

>

If you get that, just type exit at the > prompt, and then add the following lines to /etc/rc.d/rc.local

if
ps aux | grep named | grep -v grep >/dev/null ; then
echo >/dev/null
else
/usr/sbin/named
/usr/sbin/ndc restart
fi

This will check if you have a name daemon named running, and if not, it will start it, note that this is not the 100% correct way to do it, but it's by far they most lazy way to do it, and it works.


That was the basics of making a network at home and setting up a nameserver. I hope it's enough so that anyone can set up a little network at home.

===============================================================================

8 - The Init and system scripts.

============================================================= Table Of Contents

In this section I will cover the system V init, which is the most used init in Linux.

Beside the Syst V init, there are also the BSD init, which is used by Slackware and Debian and in some smaller distributions of Linux. The rest, as far as I know, uses the Syst V init. There are not so much difference of the two, I'll try to cover the differences later.

The example and files here are taken from SysVinit-2.78-6 & initscripts-5.27-37 which is compatible in some ways with the BSD init, I'll come back to that later.

So here we go:


The basic Syst V init comes with the following commands & devices:

/dev/initctl            This is the init control device.
/sbin/halt              This is to shut down the system.
/sbin/init              This is to change the init runlevel.
/sbin/killall5          This will kill everything but the script that runs it.
/sbin/pidof             This will get the PID of a Process name.
/sbin/poweroff          This will power down the system.
/sbin/reboot            This will reboot the system.
/sbin/runlevel          This will tell the init runlevel.
/sbin/shutdown          This will shut down the system.
/sbin/sulogin           This is the single user mode login.
/sbin/telinit           This is the init process control initialization.
/usr/bin/last           This shows who was in the system last.
/usr/bin/lastb          This is about the same as last.
/usr/bin/mesg           This is to toggle writable mode on your tty.
/usr/bin/utmpdump       This dumps a file for utmp (this lacks documentation)
/usr/bin/wall           This sends a message to all ttys.

And then the init needs the following extra files/dirs and commands from the initscripts package:

/bin/doexec             This lets you run a program under another name.
/bin/ipcalc             This lets you manipulate IP addresses.
/bin/usleep             This sleeps for microseconds.
/etc/X11/prefdm         This is the display manager preference file for X.
/etc/adjtime            This is the Kernel Clock Config file.
/etc/init.d             BSD init compatibility directory.
/etc/initlog.conf       This is the initlog configuration file.
/etc/inittab            This is the main init configuration file.
/etc/modules            This is where the kernel loads modules from at boot.
/etc/ppp/ip-down        This is a script for dialup internet connections.
/etc/ppp/ip-up          This is a script for dialup internet connections.
/etc/profile.d/inputrc.csh      Shell Key bindings for csh and tcsh.
/etc/profile.d/inputrc.sh       Shell Key bindings for sh and bash.
/etc/profile.d/lang.csh         Language files - i18n stuff for csh and tcsh.
/etc/profile.d/lang.sh          Language files - i18n stuff for sh and bash.
/etc/profile.d/tmpdir.csh       Set temporary directory for csh and tcsh.
/etc/profile.d/tmpdir.sh        Set temporary directory for sh and bash.
/etc/rc.d/init.d/functions      Functions for scripts in init.d
/etc/rc.d/init.d/halt           Runlevel 0 (shutdown/halt) script.
/etc/rc.d/init.d/kheader        Script to regenerate the /boot/kernel.h file.
/etc/rc.d/init.d/killall        Script to make sure everything is shut off.
/etc/rc.d/init.d/mandrake_everytime     Mandrake specific stuff.
/etc/rc.d/init.d/mandrake_firstime      Mandrake post install stuff.
/etc/rc.d/init.d/netfs          Mounts network filesystems.
/etc/rc.d/init.d/network        Bring up/down networking.
/etc/rc.d/init.d/random         Script to help random number generation.
/etc/rc.d/init.d/rawdevices     Device stuff for applications such as Oracle.
/etc/rc.d/init.d/single         Single user script (runlevel 1)
/etc/rc.d/init.d/sound          Launch sound.
/etc/rc.d/init.d/usb            Launch USB support.
/etc/rc.d/rc.local              Boot time script, (like autoexec.bat in DOS).
/etc/rc.d/rc.modules            Bootup script for modules.
/etc/rc.d/rc.sysinit            Main system startup script.
/etc/rc.d/rc0.d/S00killall      Runlevel 0 killall script link.
/etc/rc.d/rc0.d/S01halt         Runlevel 0 halt script link.
/etc/rc.d/rc1.d/S00single       Runlevel 1 single script link.
/etc/rc.d/rc2.d/S99local        Runlevel 2 local script link. (rc.local)
/etc/rc.d/rc3.d/S99local        Runlevel 3 local script link. (rc.local)
/etc/rc.d/rc4.d                 Runlevel 4 directory.
/etc/rc.d/rc5.d/S99local        Runlevel 5 local script link. (rc.local)
/etc/rc.d/rc6.d/S00killall      Runlevel 6 killall script link.
/etc/rc.d/rc6.d/S01reboot       Runlevel 6 reboot script link.
/etc/rc.local                   BSD init compatibility file.... ?
/etc/rc.sysinit                 BSD init compatibility file.... ?
/etc/rc0.d                      BSD init compatibility directory.
/etc/rc1.d                      BSD init compatibility directory.
/etc/rc2.d                      BSD init compatibility directory.
/etc/rc3.d                      BSD init compatibility directory.
/etc/rc4.d                      BSD init compatibility directory.
/etc/rc5.d                      BSD init compatibility directory.
/etc/rc6.d                      BSD init compatibility directory.
/etc/sysconfig/console          Directory for console stuff, like the keymap.
/etc/sysconfig/init             Basic init boot configurations.
/etc/sysconfig/network-scripts/ifcfg-lo         Network config for localhost.
/etc/sysconfig/network-scripts/ifdown           Turning off interfaces script.
/etc/sysconfig/network-scripts/ifdown-post      Post stuff for ifdown.
/etc/sysconfig/network-scripts/ifdown-ppp       Turning off ppp.
/etc/sysconfig/network-scripts/ifdown-sl        Turning off SLIP.
/etc/sysconfig/network-scripts/ifup             Turning on interfaces script.
/etc/sysconfig/network-scripts/ifup-aliases     Turning on alias interfaces.
/etc/sysconfig/network-scripts/ifup-ipx         Turning on IPX.
/etc/sysconfig/network-scripts/ifup-plip        Turning on PLIP.
/etc/sysconfig/network-scripts/ifup-post        Post stuff for ifup.
/etc/sysconfig/network-scripts/ifup-ppp         Turning on ppp.
/etc/sysconfig/network-scripts/ifup-routes      Turning on routes.
/etc/sysconfig/network-scripts/ifup-sl          Turning on SLIP.
/etc/sysconfig/network-scripts/network-functions     Functions for the scripts.
/etc/sysconfig/rawdevices       Raw device bindings.
/etc/sysctl.conf                System Control configurations.
/sbin/consoletype               This prints the console type.
/sbin/getkey                    Prints the key strokes....
/sbin/ifdown                    Application for the previous config files.
/sbin/ifup                      Application for the previous config files.
/sbin/initlog                   Logs msgs and events to the system logger.
/sbin/installkernel             Installs a kernel (not for manual use).
/sbin/minilogd                  * Totally lacking documentation.
/sbin/netreport                 Reports changes of the network interface.
/sbin/ppp-watch                 Application used by ifup-ppp.
/sbin/service                   Can send commands to all services etc.
/sbin/setsysfont                Sets the system font.
/usr/bin/listhome               Lists the users home directories.
/usr/sbin/detectloader          Detect the current boot loader.
/usr/sbin/supermount            Automatic mount/umount application.
/usr/sbin/sys-unconfig          System reconfiguration tool.
/usr/sbin/usernetctl            User Network interface control application.
/var/log/wtmp                   Previously logged in users entries.
/var/run/netreport              Directory for the netreport application.
/var/run/utmp                   Currently logged in users entries.

So what do you really need to know of all that ?

Well, here's the simple basics of how it works and what you need to remember.

The /etc/inittab is already explained.


Here is how the runlevels works:

The Runlevel can be one of 1 to 6 and the number means this:

0 - halt
1 - Single user mode
2 - Multiuser, without NFS
3 - Full multiuser mode
4 - Unused
5 - X11
6 - reboot

You change the runlevel with the init command, so say that you are at init runlevel 3 and you wanna go to single user mode for some reason, then you can do: init 1

In a single user mode you can only be one user, root.

And in a single user environment you can't do networking and other tasks, the runlevel 1 is meant to be there for system maintenance.

The two mostly used runlevels as default is 3 and 5. Mandrake and RedHat etc. uses Runlevel 5 as default, and so they start up with a GUI in X Windows.

Typing init 0 will shut down the system, and typing runlevel 6 will reboot the system.


What determines what the various runlevels actually start at boot time is what is in their respective directory:

Runlevel 0: /etc/rc.d/rc0.d/
Runlevel 1: /etc/rc.d/rc1.d/
Runlevel 2: /etc/rc.d/rc2.d/
Runlevel 3: /etc/rc.d/rc3.d/
Runlevel 4: /etc/rc.d/rc4.d/
Runlevel 5: /etc/rc.d/rc5.d/
Runlevel 6: /etc/rc.d/rc6.d/

So, here say that you wanna stop your web server from starting at boot time. The first thing you wanna do is to find out what runlevel you are in, that you do with the runlevel command like this:

alien:~$ runlevel
N 3
alien:~$

This means that you are in runlevel 3. So from here go to /etc/rc.d/rc3.d/ which is the directory for runlevel 3.

alien:~$ cd /etc/rc.d/rc3.d/
alien: /etc/rc.d/rc3.d/ $

Here you find the file that starts the webserver (this file is usually called httpd with a character and a number in front of it (I'll explain the character and the numbers soon), so list the contents of the current directory and find it, or just do like this:

alien: /etc/rc.d/rc3.d/ $ ls -l *httpd
lrwxrwxrwx    1 root     root       15 Dec  5 06:14 S85httpd -> ../init.d/httpd
alien: /etc/rc.d/rc3.d/ $

This says that S85httpd is a link to /etc/rc.d/init.d/httpd (../init.d/ if you're standing in /etc/rc.d/init.d/ mean /etc/rc.d/init.d/)

So just remove the link like this:

alien: /etc/rc.d/rc3.d/ $ rm -f S85httpd
alien: /etc/rc.d/rc3.d/ $

And that's how you stop something from starting with the runlevel.


Now, if you rather would have something more start with the runlevel at boot time you do like this:

You make a simple script that starts what you wanna have started and put it in /etc/rc.d/init.d/.

Say that your script's name is mystart, you are in runlevel 3 and you have made your script executable (chmod a+x mystart), and you have it in your own home directory, then you do like this:

alien: ~$ cp mystart /etc/rc.d/init.d/
alien: ~$ cd /etc/rc.d/rc3.d
alien: /etc/rc.d/rc3.d/ $ ln -s ../init.d/mystart Z00mystart
alien: /etc/rc.d/rc3.d/ $

And that's all of that.

So now, what does the Z00 in Z00mystart or S85 in S85httpd mean? Well, as the system starts it will read file after file in its runlevels directory in alphabetical order, so to get them to start in a particular order, the link names are made to determine that order. So the later in the alphabet the first character is the later it will boot, and the same for the number, the higher number the later it will start.

So A00something will start before A01something and Z99something will start later than X99something and so on.

To get something to start at boot time you can also add it as a command in the /etc/rc.d/rc.local (or for some systems /etc/rc.local) file. That file is meant to be used for single commands and not to start up major things like a server etc.

Always try to load things with the actual runlevel which is the more correct way, rather than adding them to the rc.local file.


So what's the difference between the BSD init and the System V init? The only thing that differs them that you need to remember is that they store the startup scripts in different places.

The startup scripts for the BSD init is mainly in the following places:

/etc/rc0.d/
/etc/rc1.d/
/etc/rc2.d/
/etc/rc3.d/
/etc/rc4.d/
/etc/rc5.d/
/etc/rc6.d/
/etc/rc.boot/
/etc/rcS.d/
/etc/init.d/

While the Syst V init stores its scripts mainly in:

/etc/rc.d/rc0.d/
/etc/rc.d/rc1.d/
/etc/rc.d/rc2.d/
/etc/rc.d/rc3.d/
/etc/rc.d/rc4.d/
/etc/rc.d/rc5.d/
/etc/rc.d/rc6.d/
/etc/rc.d/init.d/

In the BSD init the /etc/rc.boot/ and the /etc/rcS.d/ directories are more or less substitutes for the rc.local file since you can put things in them that starts up at boot time... what you put in /etc/rcS.d/ will even start at single user mode, so be careful what you put there.

So basically, the actual scripts goes in the init.d directory and you link them to the runlevel directory with a prefix to determine where in the bootup they should be loaded.


Here is an example of how an init script can be made. Here I made a script that would start a daemon named daemon:

#!/bin/sh
# example       Example init script that would load 'daemon'
#
# Version:      @(#) /etc/rc.d/inet.d/example 0.01 19-Feb-2001
#
# Author:       Billy (Alien), <alien a ktv d koping d se>
#

. /etc/rc.d/init.d/functions

function status() {
  ps aux | grep daemon &&
  echo "Daemon is running." ||
  echo "Daemon is not running."
}

case "$1" in
    start)
    # Check if daemon is in our path.
    if `which daemon` > /dev/null; then success || failure; fi
    echo -n "Starting Daemon"
        daemon
    echo
   ;;
    stop)
    # Check if daemon is in our path again.
    if `which daemon` > /dev/null; then success || failure; fi
    echo "Stopping Daemon"
        killall -15 daemon
   ;;
    status)
    echo "Status of Daemon:"
        status
   ;;
    reload)
    echo "Restarting Daemon."
        killall -1 daemon
   ;;
    restart)
    if `which echo` > /dev/null; then success || failure; fi
    $0 stop
    $0 start
   ;;
    *)
    echo "Usage: $0 start|stop|restart|status"
    exit 0
esac

A note is that the success and failure functions/commands come from the /etc/rc.d/init.d/functions file, which may not be present in all distributions of Linux, since it as far as I know only comes with RedHat and Mandrake.


The init's main configuration file is the /etc/inittab file, here is where you set which runlevel you wanna have, and how many consoles you want etc, so here we go:

The line where you actually set the runlevel looks like this (here runlevel 3):

id:3:initdefault:

Most RedHat like systems have runlevel 3 or 5 as default, but if you don't have any networking, you may find it better to change to runlevel 2.

Next in this file should be the system initialization.

si::sysinit:/etc/rc.d/rc.sysinit

This line tells the system the path to the rc.sysinit where it loads a lot in the system, as system clock, sets the hostname, and performs a number of checks.

Next in line is this:

l0:0:wait:/etc/rc.d/rc 0
l1:1:wait:/etc/rc.d/rc 1
l2:2:wait:/etc/rc.d/rc 2
l3:3:wait:/etc/rc.d/rc 3
l4:4:wait:/etc/rc.d/rc 4
l5:5:wait:/etc/rc.d/rc 5
l6:6:wait:/etc/rc.d/rc 6

This tells the system where to load the programs and daemons it should load for the runlevel it's in.

Say that we are in runlevel 3 (Default) then it looks at this line:

l3:3:wait:/etc/rc.d/rc 3

And there after goes to load all what's in /etc/rc.d/rc3.d/ (rc3.d or any rc?.d contains links to the real files or scripts that's located in /etc/rc.d/init.d, so if you wanna add something to your runlevel, just look how they have done it and do it in a similar fashion. and make sure to not start any network dependent application before the network starts and so on...)

Then it comes some other various stuff as trap the Ctrl+Alt+Del etc.

After this comes the tty's (Terminal Types), and there locations.

1:2345:respawn:/sbin/mingetty tty1
2:2345:respawn:/sbin/mingetty tty2
3:2345:respawn:/sbin/mingetty tty3
4:2345:respawn:/sbin/mingetty tty4
5:2345:respawn:/sbin/mingetty tty5
6:2345:respawn:/sbin/mingetty tty6

If you wanna add some more you can add like this:

8:2345:respawn:/sbin/mingetty tty8
9:2345:respawn:/sbin/mingetty tty9
10:2345:respawn:/sbin/mingetty tty10
11:2345:respawn:/sbin/mingetty tty11

And leave tty7 reserved for X-windows.

Last in the file should only be some line about xdm and its location, that is, if you have xdm installed...


And if you have read the tutorial to this point you shouldn't need any real explanation of this script.

If you still don't understand how the init scripts work, read the scripts in your system and try to understand them. And also read this section about the init and the init scripts again.

===============================================================================

9 - Basic Linux/UNIX commands and operations.

============================================================= Table Of Contents

This section is about Linux and UNIX basic commands and operations, and some other explanations and tricks, since this is not a command bible, I'll explain each command briefly, with a lot of help from the man pages and the --help argument (let's all thank the maker for cut & paste). Then again, I've seen files that have claimed to be UNIX command bibles that are even briefer and hold less commands... though most of the authors of those seems to be totally incapable of handling a UNIX and can't even spell, one of the worst examples I've seen was something like this: "The UNIX bible, in this phile is all the UNIX commandz j00 need" and after that was a list of commands without arguments... needless to say is also that 99% of all UNIX commands were missing. Anyway, enough of me making fun of those people now, and on with the tutorial. (Which isn't a UNIX command bible, just a note) I will refer to "*nix" here, and that means any sort of UNIX system, Linux, BSD, Solaris, SunOS, Xenix and so on included.


Here are the basic *nix commands, with brief explanations.

adduser
alias
apropos
awk
basename
bc
BitchX
bzcat
bzip2
cat
cc
cd
chattr
chmod
chown
chroot
cmp
cp
crontab
cut
date
dc
dd
declare
depmod
df
dhcpcd
dialog
diff
dir
dmesg
do
domainname
du
echo
eject
else
env
exit
expr
fdisk
file
find
ftpwho
g++
gcc
gdb
gpm
grep
halt
hdparm
head
help
hexdump
hexedit
hostname
id
ifdown
ifup
init
insmod
install
ipchains
ispell
kill
killall
lastlog
ldconfig
ldd
less
lilo
ln
lndir
loadkeys
locate
logout
lpq
lpr
lprm
ls
lsattr
lsmod
lsof
lynx
mail
man
mc
mesg