Open source software security

What is With Those BASH Commands?

30 November -0001

-or a short discussion of how most BASH commands function-

by Justin Keane
February 25, 2003

This article is mainly written for my ByteBack class to help explain some of the eccentricities of using Linux command line interface (CLI). Often times users get confused when CLI commands. For instance, people sometimes issue a 'ls-l' instead of an 'ls -l'. The purpose of this article is to explain the structure of these commands and how to issue them properly.

The typical BASH command is actually an executable. For instance, when you type in 'ls' you're actually firing off the program ls which is found (typically) in /bin. If you issue the command 'whereis ls' you should see the location of your ls program, and the program entry should look something like this in your /bin directory:

-rwxr-xr-x    1 root     root        48316 May 10  2002 ls*

Its an executable. The reason you can type 'ls' from any location any fire off the ls program (whereas with other programs you may have to type './' and the program name) is that the /bin directory is part of your user profile. If you go to your home directory you will find a hidden file called .bash_profile. Looking at this file should reveal something like this:

  
# .bash_profile

# Get the aliases and functions
if [ -f ~/.bashrc ]; then
        . ~/.bashrc
fi

# User specific environment and startup programs

PATH=$PATH:$HOME/bin

export PATH
unset USERNAME

You will see that /bin is listed in your 'PATH' variable. This is the path the computer searches along when you issue any command. You can add entries to your PATH so that you can search non-standard locations for programs by adding a new line to the .bash_profile like so:

# .bash_profile

# Get the aliases and functions
if [ -f ~/.bashrc ]; then
        . ~/.bashrc
fi

# User specific environment and startup programs

PATH=$PATH:$HOME/bin
PATH=$PATH:/home/jkeane

export PATH
unset USERNAME

Lets try this principle out. To start lets make a simple shell script. A shell script is a file that basically performs a bunch of CLI commands at once. Start in your home directory and create a new file called 'hello.sh' using pico or vi or whatever text editor you want. For me, I'll use:

[jkeane@madirish jkeane]$ pico hello.sh

This fires up pico and creates a new file called hello.sh. Type this into the file:

echo "hello world"

Then save the file and quit. Now we're going to have to make the file executable so it will actually 'run'. Do this by issuing a chmod command to change the permissions on the file like so:

[jkeane@madirish jkeane]$ chmod +770 hello.sh

Now you can run the program by typing:

[jkeane@madirish jkeane]$ ./hello.sh

However, if yout type:

[jkeane@madirish jkeane]$ hello.sh

Nothing will happen. This is because without the './' the computer will search your PATH and look in /bin for the program hello.sh (which isn't there). Now update your .bash_profile like I did above to include your home directory in the PATH and you'll be able to type 'hello.sh' from any location and the computer will find the 'hello.sh' program in your home directory (it will search /bin and /home/username for the program and find it in /home/username and fire it off). Ok, so now we understand about executables. This should explain why issuing a command like

[jkeane@madirish jkeane]$ ls-l

will fail. The computer searches the /bin directory for the program 'ls-l' and doesn't find it. That leaves us with a discussion of command syntax. The syntax for a basic command is:

command [arguments] [parameters]

The command has to be the program name EXACTLY - proper capitalization and everything. If you put a space after the program name the computer will interpret everything else as arguments to that command. Lets take a look at a simple C program that utilizes arguments:

/*      HELLO.C -- Hello, world */

#include <stdio.h>

int main (int argc, char *argv[])
{
        printf("argument one = %s\n", argv[1]);      

        return 0;
}

Ok, this may look a little weird to a non-programmer so lets examine the code. Line one is a comment, it does nothing. The second line (the one that starts with the '#') is an include that compile the header file stdio.h into the program, all this does is allow the program to take arguments (parameters). Line three starts the program and tells it to look at any strings following the program name when the program is invoked. These strings are passed to an array. C differentiates the arguments based on a space delimiting them. When you fire this program using:

[jkeane@madirish jkeane]$ ./hello these are parameters

C recognizes three parameters, 'these', 'are', and 'parameters'. The next line uses a placeholder (%s) and substitutes the placeholder with argv[1] or the first argument following the program command. Thus the program prints out the first argument or:

these

If you have gcc installed (check using 'rpm -q gcc') you can create this program by creating a new text file called hello.c (in pico or vi or whatever) and copying the code. Once you're done save the file and compile it using

[jkeane@madirish jkeane]$ gcc -o hello hello.c

Then you can fire the program using:

[jkeane@madirish jkeane]$ ./hello these are parameters

and you can watch the output. Ok, back to how BASH programs work. You should understand now that anything following the program name is interpreted as a parameter. Standard BASH programs differentiate different types of parameters based on whether or not they are preceded with a '-' or not. Everything that starts with a '-' is considered a flag or argument. Thus when you enter:

[jkeane@madirish jkeane]$ ls -l

The shell will fire the ls program with one parameter ('-l') and because the '-l' begins with a dash, the ls program knows it is a flag. This particular flag tells the ls (or list) program to list long file listings. If we want to list all files (including hidden files) we can use the -a flag like so:

[jkeane@madirish jkeane]$ ls -a

Now if we want to list all programs using the long listing you can issue:

[jkeane@madirish jkeane]$ ls -l -a

and the ls command knows that the two arguments are both flags since they begin with a dash, or you can use:

[jkeane@madirish jkeane]$ ls -la

and the ls command will find one parameter, but since 'la' is an unrecognized flag it will strip it apart and use the 'l' flag AND the 'a' flag. Now if you add other parameters to the command, after the flags, the program will interpret those differently when you don't preceed them with a dash. For instance:

[jkeane@madirish jkeane]$ ls -la /home/jkeane

Will find two parameters, the first is comprised of '-la' which is interpreted as two flags, and the second parameter '/home/jkeane' since it isn't a flag will be interpreted as the ls commands target. Thus, issuing this command will list the directory contents (in long and all files format) of the directory specified by the second parameter (the /home/jkeane directory).

The basic point of all of this is that you need to be careful in using spaces and dashes following a command. If you want to find out what all flags and parameters you can use for a specific command use the 'man' command. So you can use 'man ls' to find out what legal flags and parameters are recognized by the 'ls' program as well as their proper syntax.