arminstraub.com

Working with the Bash

This is a rather random collection of examples illustrating various features of the Bash.
A nice resource for scripting on the shell is the following Bash Scripting FAQ.

Working on multiple files

The convert tool from imagemagick allows you to convert between image formats (and much more!). To convert all bmp files to jpg:

$ for F in *.bmp; do
> convert "$F" "${F%.*}.jpg"; done

Another example is the following; suppose you want to endow all subdirectories of the current directory with execution rights (which is usually the case). You could do the following:

$ find . -type d -exec chmod a+x {} \;

Reading a file linewise

To work with the lines of a file, or more generally with the lines of the output of any command, you can use something like:

$ cat file | while read LINE; do
> echo $LINE
> done

Of course, instead of echo $LINE you could do something more useful.

Counting the number of files

Here are two ways to count the number of files in a directory. Both are kind of work-arounds but might serve as food for thought.

$ COUNT=$(( $(ls -l | wc -l) - 1))
$ COUNT=$(ls -1 | wc -l)

Searching and replacing in files

To replace searchfor with replacewith in all *.java files you can do

$ sed -i -e "s/searchfor/replacewith/g" *.java

If you want to include all files in any subdirectory of the current directory you can instead use

$ find -name "*.java" \
> | xargs sed -i -e "s/searchfor/replacewith/g"

Generating numbers

To loop over all numbers from 1 to 10 you can use

$ for ((N=1;N<=10;N+=1)); do echo $N; done

Often, for instance when numbering files, you want to have 01, 02, ... instead of 1, 2, ... This can be achieved using printf.

$ for ((N=1;N<=10;N+=1)); do
> echo $(printf "%02d" $N); done

Renaming several files

When renaming several files according to patterns the tool mmv comes in very handy. For instance, to rename all files of the form homework-... to problem-... you can simply use

$ mmv "homework-*" "problem-#1"

For more complex tasks there is also the tool rename that makes use of Perl regular expressions.

Using aliases

You can use alias to create shortcuts for longer commands.

$ alias thumbs='mkdir -p thumbs && for f in *.jpg;
> do convert -resize 400x200 $f thumbs/$f; done'

In more complicated situations you can create a function which allows you to use paramaters via $n.

$ function mcd() { mkdir -p "$1" && cd "$1"; }

Of course, both aliases and functions are most useful when saved for instance in ~/.bashrc.

Configuring a nice prompt

The (primary) prompt is what you see before the cursor when you're about to type a command. When you continue to enter a command on a next line (for instance using \) then you see the secondary prompt.

$ echo "this is \
> an example"

These two prompts are stored in the shell variables $PS1 und $PS2.

notebook:~ $ echo $PS1
\h:\w \$

For a complete list of possibilities see man bash:

\t, \T, \@, \A current time (HH:MM:SS, HH:MM:SS (12 hours), HH:MM AM/PM, HH:MM)
\d, \D{format} current date (weekday month day, as formatted by strftime)
\w, \W working directory (complete path, only top directory)
\h, \H hostname (up to the first '.', complete)
\u current user
\$ "#" for root and "$" for other users
Note: in the Bash $ has to be escaped as "\\$".
Or one uses: '\$'
\[, \] Enclose color or font style codes
`cmd` Displays the result of running cmd.
Note: you need to use "`" instead of "'".

You can test new prompts as follows before permanently storing them for instance in ~/.bashrc.

$ PS1='\u [\w] \$ '
root [~] # 

A prompt I use is the following.

12:55:06 /usr/src # echo $PS1
\[\033[36m\]\t \[\033[00m\]\w \[\033[01m\]\$ \[\033[00m\]
12:55:10 /usr/src # echo $PS2
\[\033[01m\]> \[\033[00m\]