Thursday, 1 November 2007

Bash programming

The standard shell under Linux is called Bash (the GNU Bourne Again SHell). Even though people are generally used to do a lot of stuff using graphical user interfaces, the command prompt can be very convenient for some tasks. Here are a few simple examples of how to get things done using your keyboard rather than your mouse.

Command line use by example

To convert all .gif files in a directory to .jpg, type
for file in *.gif; do convert ${file} ${file%gif}png; done

To find all .tex files in a directory including the subdirectories, type
find . -name "*.tex"

To filter out those files that contain the word "dimension", use
grep dimension `find . -name "*.tex"`

The code between the backquotes (`) is evaluated first and the output it generated is listed as if you typed it at the end of the command. In Bash you can also use $(command) as an alternative to the backquotes, which has the benefit that it can be nested. For example to get the number of bytes of all tex-files that contain the word dimension, you can say
du -s -k $(grep -l dimension $(find . -name "*.tex"))

To make the search on "dimension" case insensitive, use
grep -i dimension `find . -name "*.tex"`

To count the number of occurences, use
grep -i dimension `find . -name "*.tex"` | wc -l

which might be written shorter - but less illustrative - as
grep -c -i dimension `find . -name "*.tex"`

I'm sure you can use these examples to do powerful text searches yourself.

To rename a bunch of .gif files in a directory to new names like 001.gif, 002.gif etc., you could type

for f in *.gif; do
mv $f $(printf '%03d' $l).gif

This example also shows how to use if statements. A simple for loop can be programmed as
for (( n = 1 ; n < 9 ; n++ )); do echo $n; done

Writing scripts

If you have many commands that you use more than once, you can also create a text file in your favourite editor, type #!/bin/bash as the first line, and then put some shell commands. If you save the file and make it executable with chmod (see below), you have written a shell script and can simply execute all command by typing the script's name. This is like creating a Matlab script versus typing commands in the Matlab command window. In bash scripts, you can use a couple of funny looking variable names that have special meaning:

Variable Meaning
$0 name of the script
$# number of arguments given on the command-line when calling the script
$1 first argument given to the script
$* all arguments
$@ all arguments
$$ PID of the script

The difference between $* and $@ is subtle. Usually the latter does what you think it will do, while the first one has a slightly different semantic meaning. If you say "$*" it will expand to the single string "$1$IFS$2$IFS$3...", where IFS is an environment variable that contains a space by default but might have another value, e.g. the character ':'. When you say "$@" it will expand to the list of strings "$1" "$2" "$3"..., which is usually what you mean.

No comments: