KSH tips and tricks

Various Shell Prompt Tips

C-U - Clear the prompt line

Add prompt editing using VISUAL. TBD.

Customization of shell prompt. Add the following to .profile.

Make shell prompt more informative

HOST=`hostname`
export PS1='${USER}@${HOST%%.*} ${PWD##*/} # '

push and pop directories

pushd and popd is really useful when working in the command prompt. pushd <dir> push current directory on a directory stack and change currend directory to <dir>. popd change current directory to the laste pushed directory on stack.

cd /home/peter
pushd /root
popd

pushd and popd is part of csh but not in ksh.

In ksh you may use cd - and cd -- to go back 1 and 2 folders in history. This also works in csh.

cd /home/peter
cd /root
cd -

Command substitution

Command subtitution is performed by $( ) or ` ` notation. The first is recommended for compatibility reasons.

One thing to note abount ksh is that it removes all trailing newline characters when performing command substitution. See following example.

# echo $(ls)
file1 file2 file3

To preserve newline characters you can the substituted command in " ".

# echo "$(ls)"
file1
file2
file3

See Command substitution in the Korn shell or POSIX shell for more information.

String Operators

Operator Substitution
${ varname :- word }	
If varname exists and isn't null, return its value; otherwise return word.

Purpose: Returning a default value if the variable is undefined.

Example:	
${count:-0} evaluates to 0 if count is undefined.

${ varname := word}	
If varname exists and isn't null, return its value; otherwise set it to word and then return its value.[7]

Purpose: Setting a variable to a default value if it is undefined.

Example:	
$ {count:=0} sets count to 0 if it is undefined.

${ varname :? message }	
If varname exists and isn't null, return its value; otherwise print varname : followed by message , and abort the current command or script. Omitting message produces the default message parameter null or not set .

Purpose: Catching errors that result from variables being undefined.

Example:
{count :?" undefined! " } prints "count: undefined!" and exits if count is undefined.

${ varname :+ word }	
If varname exists and isn't null, return word ; otherwise return null.

Purpose: Testing for the existence of a variable.

Example:	
${count:+1} returns 1 (which could mean "true") if count is defined.

See Learning the Korn Shell - Ch 4.

Editing mode

ksh can (as other shells) work in either emacs (default) or vi mode. Some commonly used commands for emacs mode are.

CTRL-A	 Move to beginning of line
CTRL-E   Move to end of line
CTRL-K	 Delete ("kill") forward to end of line
CTRL-W   Delete ("kill") one word backwards
ESC-B    Move one word back (ALT-RIGHT also works on Mac)    
ESC-F    Move one word forward (ALT-LEFT alsto works on Mac)

See Emacs Edit Mode.

If you want to switch to vi editing mode simply do.

set -o vi
set -o emacs    # go back to emacs mode

Some useful vi editing commands

ESC  escape to command mode
i    enter insert mode (initial mode)
w    Move one work forward (command mode)
b    Move one work backwards (command mode)
cw   Remove current word and enter insert mode (command mode) 

Diffuculties with sub-shells

See 8.6 Subshells in Learning the Kort Shell for an overview.

The problem is that it can be difficult to know when a code block is run in a sub-shell or not. Some implementations differ as well. One difference between code blocks and code blocks run in a sub-shell doesn't is that sub-shells doesn't inherit shell variables to (and from) the parent shell. See the following example. Also see while read loop scope variables for an explanation.

#!/bin/ksh
 
# Here the while code block is run in the parent shell
IFS=','
while read a b c ; do
  pa=$a
  pb=$b
  echo "$a,$b"
done << EOF
`echo "a,b"`
EOF

echo $a         # These are empty as last line is EOF
echo $b
echo $pa        # These are printed
echo $pb

# While this variant seems to create a sub-shell where env. variables are not accessible
echo "a,b" | while read d e f ; do
  pd=$d
  pe=$e
  echo "$d;$e"
done 

echo $d         # None of these are set due inaccessible env. variables
echo $e
echo $pd
echo $pe

This is just one of the strange things that may happen in shell scripts.

Proper escaping with awk

See the folloing functions that print column n specified in $1 from a ; separated string specified in $2. awk want the command to be enclosed in single quotes ('), but that also means that ksh will leave that string un-evaluated. The solution is to enclose the complete awk command in a double quote string (") and evaluate it using eval command. The $1 string will be evaluated to the column number (e.g. "2") so the resulting awk command will be awk -F'[;]' '{ print $2 }'. The dollar sign must be escaped when inside double quotes to disable ksh variable substitution for those.

# Print column n (1..) in $1 from string in $2 with ; as separator
col() {
  # eval is used to expand $1 
  echo "$2" | eval "awk -F'[;]' '{ print \$"$1" }'"
}

Command history (in ksh)

ksh does support command history just as e.g. bash does. Command history is stored by default in $HOME/.sh_history. But a custom history file can be used by setting HISTFILE environment variable.
History can be shown using fc (in ksh) and/or history (in csh). In ksh history is usually aliased to fc -l. Default fc editor is ed but can be changed with FCEDIT environment variable.

fc -l           # or history
fc -e - ls      # call last ls command