Other Pages
- Start off with a shebang
- How to generate and use ssh keys .
- Setting up Java classpath using a shell script Classpath using shell.
- sed one liners
- Reading a file line by line with shell
- Finding a property in a Java-style properties file with shell
- Bash Reference Manual
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!
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:
- PATH is not converted. That's because Cygwin uses PATH.
- 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
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 |
Add Comment