In the first bash tutorial we went over brace expansions and a few history tricks. The goal of this post is to expand on that and teach more bash features.
Have you ever wondered when you typed a previous command in your history? This is easy to do with the $HISTTIMEFORMAT variable and bash >= 3.0. $HISTTIMEFORMAT accepts standard strftime(3) format strings.
jeff@beastmaster:~$ export HISTTIMEFORMAT="%m/%d/%y - %H:%M:%S " jeff@beastmaster:~$ history | tail -n 75 411 06/11/08 - 15:36:09 sudo apt-get install network-manager-dev libmozjs-dev libmozjs0d 412 06/11/08 - 15:36:22 make clean && ./configure 413 06/11/08 - 15:36:30 make 414 06/11/08 - 15:36:54 apt-cache search dbus 415 06/11/08 - 15:36:59 apt-cache search dbus | grep dev
NOTE: The first time you set $HISTTIMEFORMAT, all previous commands inherit the current time. Everything afterwards is saved with a proper timestamp.
In the previous tutorial we covered usage of shell history modifiers like !vi or !?passwd to run previous commands. The only problem with those is that they execute the command directly without letting you edit them. Enabling the histverify shell option lets you edit the command before running it.
jeff@beastmaster:~$ shopt -s histverify jeff@beastmaster:~$ !vi jeff@beastmaster:~$ vi src/libproxy/src/Makefile
$CDPATH is a variable similar to $PATH, but it defines a search path for the cd command.
Given a directory structure like below, lets say that /home/jeff/svn/systems is one of your most frequently accessed directories.
/home/jeff/svn /home/jeff/svn/systems
jeff@beastmaster:~$ export CDPATH=/home/jeff/svn jeff@beastmaster:~$ pwd /home/jeff jeff@beastmaster:~$ cd systems /home/jeff/svn/systems jeff@beastmaster:~/svn/systems$ pwd /home/jeff/svn/systems
Cool huh? The last set of tricks for today are bash’s powerful parameter substitutions. Here is a non-exhaustive list along with a few examples. The open group has further information on all possible parameter expansions in posix compatible shells.
| ${parameter:-word} | Substitute word if parameter is null or non-s et. Otherwise, use $parameter as normal. |
| ${parameter:=word} | If $parameter is unset of null, set the value to word and substitute it’s value in-place. |
| ${parameter:+word} | If $parameter is set and non-null, substitute word. Otherwise, substitute nothing. |
| ${parameter/foo/bar} | If parameter is set and contains the value foo, replace foo with bar and print the result. |
jeff@beastmaster:~$ jeff@beastmaster:~$ parameter=digitalprognosis.com
jeff@beastmaster:~$ echo $parameter
digitalprognosis.com
jeff@beastmaster:~$ unset parameter
jeff@beastmaster:~$ echo $parameter # Empty
jeff@beastmaster:~$ echo ${parameter:-linux.com} # Display, but don't set the variable
linux.com
jeff@beastmaster:~$ echo $parameter # Empty
jeff@beastmaster:~$ echo ${parameter:=ubuntu.com} # Sets parameter to ubuntu.com
ubuntu.com
jeff@beastmaster:~$ echo $parameter
ubuntu.com
jeff@beastmaster:~$ echo ${parameter:+redhat.com} # Displays because parameter is set
redhat.com
jeff@beastmaster:~$ echo $parameter
ubuntu.com
jeff@beastmaster:~$ echo ${parameter/ubuntu/canonical} # Very simple sed feature-set
canonical.com
jeff@beastmaster:~$ echo $parameter
ubuntu.com
Jul 17th, 2008 at 10:26 am
Nice tips, Jeff. I’d like to see more of this :)
Anyway, just one note:
when using parameter substitution (:-, :+, :=), i think that one more thing needs to be said: if you use it with “:” sign (:-, :+, :=) then it checks if parameter is unset (set) OR null (if var is set to NULL value, var is considered unset). If you use it without “:” character (-,+,=), it checks only if parameter is set (unset) (if var is set to NULL value, var is considered set).
Jul 17th, 2008 at 12:10 pm
From this post, “${parameter:-word} Substitute word if parameter is null or non-set. Otherwise, use $parameter as normal.”
You bring up a good point, but I already said the same thing :)