Unix Shell

Other Pages

One liners

Get the filename and directory of the currently running script

SCRIPT_NAME=$\{0##*/\}
SCRIPT_DIR=`dirname $0`

Print out the current date and time

The date command displays the current date and time when used with no arguments:

josh@josh-desktop:~$ date
Thu Jul 15 11:43:49 EDT 2010

To use a more numeric format (like Log4J, for example), use the '+' option:

josh@josh-desktop:~$ date '+%F %r'
2010-07-15 11:41:44 AM

Diff two directories, only show which files are different

diff \-rq somedir someotherdir

Merge stderr into stdout

Use 2>&1, for example:

somecommand 2>&1 > someoutput.log

Get the extension of a file

In bash, use ${var/*./}

For example:

myfile=thefile.txt
myext=$\{myfile/*./\}

Results in myext being '.txt'

Shell Programming

Start with a shebang!

See Start off with a shebang

Launching a nested shell from a shell script

Nested shells can be really useful for setting up environment variables, PATH, and LD_LIBRARY_PATH in a clean way. You could just source in a shell script that sets environment varaibles, etc, but in the nested shell it is much easier to return to the un-touched environment by typing exit.

#!/bin/bash
... set up environment variables and PATH ...
... exports ...
exec $SHELL

Cygwin compatibility

If you are using Cygwin, you need to do a few extra things to 'path names' and other structures before invoking non-Cygwin commands. ANT is a good example because it is run under Java, which doesn't know about Cygwin paths.

Here is an example of setting ANT_HOME from a shell script:

#!/bin/sh
ANT_HOME=/cygdrive/c/java/apache-ant-1.6.5
JAVA_HOME=/cygdrive/c/java/jdk1.5.0_10
PATH=$ANT_HOME/bin:$JAVA_HOME/bin:$PATH
ANT_HOME=`cygpath --mixed "$ANT_HOME"`
JAVA_HOME=`cygpath --mixed "$JAVA_HOME"`
export ANT_HOME
export JAVA_HOME

Of course, this won't work on Linux, so it could be made more portable like this:

#!/bin/sh
UNAME=`uname`
case "$UNAME" in
    CYGWIN*)
        ANT_HOME=/cygdrive/c/java/apache-ant-1.6.5
        JAVA_HOME=/cygdrive/c/java/jdk1.5.0_10
        ;;
    *)
       ANT_HOME=/opt/apache-ant-1.6.5
       JAVA_HOME=/usr/java/jdk1.5.0_10
       ;;
esac

PATH=$ANT_HOME/bin:$JAVA_HOME/bin:$PATH

case "$UNAME" in
    CYGWIN*)
        ANT_HOME=`cygpath --mixed "$ANT_HOME"`
        JAVA_HOME=`cygpath --mixed "$JAVA_HOME"`
        ;;
    *)
        # Nothin' doin on linux.
        ;;
esac

export ANT_HOME
export JAVA_HOME

Note:

  1. PATH is not converted. That's because Cygwin uses PATH.
  2. JAVA_HOME and ANT_HOME are converted 'after' PATH is set because ant doesn't know about Cygwin's path system, but Cygwin bash does.

Script name and script path

See Start off with a shebang

Full path names

To get the full path name from a relative path name:

RELATIVEPATH=".."
ABSPATH=`cd $RELATIVEPATH && pwd`

Note that the 'cd' command inside the back-ticks does not affect the current directory of the running script.

To get the full path of the parent directory of the current script:

#!/bin/sh
SCRIPT_DIR=`dirname $0`
PARENT_DIR=`cd $SCRIPT_DIR/.. && pwd`

Shell Gotchas

Boolean Logic Expressions - equality, AND, OR

Boolean logical expressions, in if and while statements for example, are a little different in shell. A Java programmer might be tempted to write:

if [[ -f somefile.txt && ! -f someotherfile.txt ]] ; then
  ... do some stuff ...
fi

This will normally produce a [: missing `]' error because && was used for a logical AND instead of -a. The correct code is:

if [[ -f somefile.txt -a ! -f someotherfile.txt ]] ; then
  ... do some stuff ...
fi
Operation Other Languages Shell expression operator
Logical AND && (Java and C++), AND -a
Logical OR || (Java and C++) -o
Equals == (Java and C++) -eq

Labels

shell shell Delete
linux linux Delete
Enter labels to add to this page:
Please wait 
Looking for a label? Just start typing.