Thursday, December 18, 2008

Connecting and Expanding Commands in Linux Shell

A truly powerful feature of the shell is the capability to redirect the input and output of commands to and from other commands and files. To allow commands to be strung together, the shell uses metacharacters. As noted earlier, a metacharacter is a typed character that has special meaning to the shell for connecting commands or requesting expansion.

Piping Commands
The pipe (|) metacharacter connects the output from one command to the input of another command. This lets you have one command work on some data, and then have the next command deal with the results. Here is an example of a command line that includes pipes:

$ cat /etc/password | sort | less

This command lists the contents of the /etc/password file and pipes the output to the sort command. The sort command takes the usernames that begin each line of the /etc/password file, sorts them alphabetically, and pipes the output to the less command (to page through the output).

Pipes are an excellent illustration of how UNIX, the predecessor of Linux, was created as an operating system made up of building blocks. A standard practice in UNIX was to connect utilities in different ways to get different jobs done. For example, before the days of graphical word processors, users created plain-text files that included macros to indicate formatting. To see how the document really appeared, they would use a command such as the following:

$ gunzip < /usr/share/man/man1/grep.1.gz | nroff -c -man | less

In this example, the contents of the grep man page (grep.1.gz) are directed to the gunzip command to be unzipped. The output from gunzip is piped to the nroff command to format the man page using the manual macro (-man). The output is piped to the less command to display the output. Because the file being displayed is in plain text, you could have substituted any number of options to work with the text before displaying it. You could sort the contents, change or delete some of the content, or bring in text from other documents. The key is that, instead of all those features being in one program, you get results from piping and redirecting input and output between multiple commands.

Sequential Commands
Sometimes you may want a sequence of commands to run, with one command completing before the next command begins. You can do this by typing several commands on the same command line and separating them with semicolons (;):

$ date ; troff -me verylargedocument | lpr ; date

In this example, I was formatting a huge document and wanted to know how long it would take. The first command (date) showed the date and time before the formatting started. The troff command formatted the document and then piped the output to the printer. When the formatting was done, the date and time was printed again (so I knew how long the troff command took to complete). Another useful command to add to the end of a long command line is the mail command. You could add mail -s “Finished the long command” to the end of a command line. Then, for example, a mail message is sent to the user you choose after the command completes.

Background Commands
Some commands can take a while to complete. Sometimes you may not want to tie up your shell waiting for a command to finish. In those cases, you can have the commands run in the background by using the ampersand (&).

Text formatting commands (such as nroff and troff, described earlier) are examples of commands that are often run in the background to format a large document. You also might want to create your own shell scripts that run in the background to check continuously for certain events to occur, such as the hard disk filling up or particular users logging in. Here is an example of a command being run in the background:

$ troff -me verylargedocument | lpr &

Expanding Commands
With command substitution, you can have the output of a command interpreted by the shell instead of by the command itself. In this way, you can have the standard output of a command become an argument for another command. The two forms of command substitution are $(command) and `command` (backticks, not single quotes). The command in this case can include options, metacharacters, and arguments. Here is an example of using command substitution:

$ vi $(find /home | grep xyzzy)

In this example, the command substitution is done before the vi command is run. First, the find command starts at the /home directory and prints out all files and directories below that point in the file system. The output is piped to the grep command, which filters out all files except for those that include the string xyzzy in the filename. Finally, the vi command opens all filenames for editing (one at a time) that include xyzzy. This particular example is useful if you want to edit a file for which you know the name but not the location. As long as the string is uncommon, you can find and open every instance of a filename existing beneath a point you choose in the file system. (In other words, don’t use grep a from the root file system or you’ll match and try to edit several thousand files.)

Expanding Arithmetic Expressions
There may be times when you want to pass arithmetic results to a command. There are two forms you can use to expand an arithmetic expression and pass it to the shell: $[expression] and $(expression). Here is an example:

$ echo “I am $[2008 - 1957] years old.”
I am 51 years old.

The shell interprets the arithmetic expression first (2008 - 1957), and then passes that information to the echo command. The echo command displays the text, with the results of the arithmetic (51) inserted. Here’s an example of the other form:

$ echo “There are $(ls | wc -w) files in this directory.”
There are 14 files in this directory.

This lists the contents of the current directory (ls) and runs the word count command to count the number of files found (wc -w). The resulting number (14 in this case) is echoed back with the rest of the sentence shown.

Expanding Environment Variables
Environment variables that store information within the shell can be expanded using the dollar sign ($) metacharacter. When you expand an environment variable on a command line, the value of the variable is printed instead of the variable name itself, as follows:

$ ls -l $BASH
-rwxr-xr-x 1 root root 625516 Dec 5 11:13 /bin/bash

Using $BASH as an argument to ls -l causes a long listing of the bash command to be printed. The following section discusses shell environment variables.

Source of Information : Linux Bible 2008 Edition

No comments: