Shell Tips

Index

How to improve your typing speed in the shell

The OS or the shell define some useful character sequences which can improve your typing speed in the shell. For example the sequence ^W deletes the word on the left of the cursor. Or the character ^U is useful when inserting a password: you can press ^U once to delete the entire password instead of hitting backspace many times. If a character must be inserted verbatim in the shell (e.g. a TAB character), press first ^V. The following table lists some of the most useful character sequences:

characterdescriptiondefined by
^Dend of file (EOF)POSIX.1 Terminal I/O
^Vliteral next (LNEXT)POSIX.1 Terminal I/O
^Hbackspace one character (ERASE)POSIX.1 Terminal I/O
^Uerase line (KILL)POSIX.1 Terminal I/O
^Wbackspace one word (WERASE)POSIX.1 Terminal I/O
!xxxfind in history the command beginning with xxxshell
^Rfind character sequence in history (completion mode)GNU readline
^Gescape from completion modeGNU readline
^Ago to the begin of the lineGNU readline
^Ego to the end of the lineGNU readline

Backticks vs. $()

The two following lines are equivalent on most shells (all POSIX shells):

sh$ foo=`echo bar`
sh$ foo=$(echo bar)

It is thus possible to use one or the other form equally though $() can be more easily nested. The only drawback of $() is that it is not accepted by some older shells (e.g. Bourne shell). Portable scripts should use Backticks.

test vs. [ ]

The two programs test and [ (UNIX allows many characters in file names, even "[") are exactly the same. Sometimes the command [ is a link to test, with the difference that [ requires a "]" as last argument. It is a matter of taste whether to use one ore the other form. Be sure to put always a space between the closing bracket and the last argument to [, otherwise the closing bracket will not be separated from the last argument.

Calculations in the shell

Simple calculations can be done with $(()). For example, i=$(($i+1)) increments i by 1. If integer arithmetic is not enough, bc or dc can be used. The following example prints the fraction 1/3 with four digits precision.

sh$ echo 'scale=4; 1/3' | bc

The standard Unix tool awk can be used for more complex operations which contain loops, function calls, input parsing etc.

How to filter out comments from configuration files

The following sed script prints a configuration file in a compact form on the screen, omitting blank lines and comments (beginning with #)

sh$ sed -e 's/#.*//; /^$/d'

You can use it as filter or by appending the file name at the end of the command.

Finding out the process id / killing processes

This could be done with a combination of ps, sed and kill if there weren't already pgrep, pkill and killall doing this job.

The following example shows how to avoid printing "grep program" when calling ps (ps ax | grep program):

sh$ ps ax | grep [p]rogramm

rot-13

Sometimes (especially in Usenet) texts are 'encrypted' with rot-13. This means that the alphabet is rotated by 13 positions: "a" becomes a "n", "b" becomes "o" etc. The following command encrypts and decrypts texts with the rot-13 'algorithm':

sh$ tr "[a-zA-Z]" "[n-za-mN-ZA-M]"

The same program can be used to both encrypt and decrypt texts, because the English Alphabet contains 26 letters.

String manipulations in the shell

The man page of the bash documents some very useful (though widely unused) features in the chapter Parameter Expansion. Some of the most interesting are:

${parameter}
This simple kind of parameter expansion is equivalent to $parameter. It may be useful when the variable is followed by other letters, e.g:
sh$ x=camel
sh$ echo ${x}ot
camelot
${#parameter}
Is the length of the string in parameter. If parameter is * or @, the value substituted is the number of positional parameters.
${parameter#word}
${parameter##word}
Expands to word; but if word matches the beginning of $parameter, then the shortest match (#) or the longest match (##) is deleted. This can be used for example to obtain the suffix of a known file name. e.g.:
sh$ file=track.mp3
sh$ echo ${file#track}
.mp3
${parameter%word}
${parameter%%word}
Expands to word; but if word matches the end of $parameter, then the shortest match (%) or the longest match (%%) is deleted. This can be used for example to cut the suffix of a file name. e.g.:
sh$ file=track.mp3
sh$ echo ${file%.mp3}
track
${parameter/pattern/string}
${parameter//pattern/string}
This command can be used to substitute in parameter one (/) or more (//) times the pattern with string. e.g.:
sh$ file=track.mp3
sh$ echo ${file/.mp3/.ogg}
track.ogg

A signature virus

I've seen the following script in Usenet (and naturally I've started it immediately...). It is equivalent to common Windows viruses, with the difference that the designed victim must paste the code into a shell... I assume as proven the fact that *nix is as well vulnerable as Windows by viruses; it is only more laborious to get infected.

sh$ :(){ :|:&};:

Once the program has been started, it blocks the shell (in fact, it is a fork bomb). The script will be more readable if we write the function defined in the script not as ':', but, let's say, 'g':

sh$ g(){ g|g&};g

The script defines the function g, which calls itself in pipe with another instance of itself, and both processes are executed in the background (&). The last command in the script starts the disaster. Before you try to start the program, it would be better to limit the maximum number of processes to a reasonable limit by typing ulimit -u 50.