Other Stuff

And here's stuff that I cant fit anywhere else :-)

eval

The eval command is a way to pretend you type something directly. This is a very dangerous command. Think carefully before using it.

One way of using eval, is to use an external command to set variables that you do not know the name of beforehand. Or a GROUP of variables. A common use of this, is to set terminal-size variables on login:

eval `resize`

Backticks

There are ways to put the output of one command as the command line of another one. There are two methods of doing this that are basically equivalent:
echo This is the uptime: `uptime`
echo This is the uptime: $(uptime)
Technically, the second one is the POSIX-preferred one.

In addition to creating dynamic output, this is also very useful for setting variables:

datestring=`date`
echo "The current date is: $datestring"

printf string formatting and time

Speaking of date: ksh has a special builtin, within another one.

ksh has a builtin printf function, which many people may be familiar with from other languages such as C. The expected modifiers mostly apply. However, ksh has an extra modifier: "%T".

"%T" is related to Time output. It gives ksh a built-in "date" like function, except it's even more flexible. It can deal with unixseconds, and it can PARSE dates, in addition to outputting them.

It has many options, and a special relation to keyword "now". It has two forms of syntax:

   A)    %T                         # default 'date' type output

   B)    %(%date%modifiers%here)T   # modifiers that 'date' takes
For instance:
    ###  print current time in normal format
    $ printf "%T\n" now
    Sat Aug 24 14:22:22 GMT 2019

    ###  print current time in unixseconds
    $ printf "%(%s)T\n" now
    1566656615

  
It does follow the printf convention of using "%" format placeholders, and thus needs an additional argument to printf to format. In the above examples, we used the special keyword argument of "now". However, you can specify other times. ksh gives you a lot of flexibility in how to specify it. Here are just a few examples.

Print out date from unixseconds number (note mandatory '#' and quotes around the number)

    $ printf "%T\n" "#1566656615"
    Sat Aug 24 14:52:17 GMT 2019
Use of relative verbal time
    $  printf "%T\n" "tomorrow at noon"
    Sun Aug 25 12:00:00 GMT 2019

    $ printf "%T\n" "a week ago"
    Mon Apr 15 00:00:00 GMT 2019

Parse verbal time, in standard form and relative form.
    $ printf "%(%a)T\n" "final day june 2001"
    Sat

    $ printf "%(%s)T\n" "Sat Aug 24 14:52:17 GMT 2019"
    1566656615

Text positioning/color games

This is actually a huge topic, and almost deserves its own tutorial. But I'm just going to mention it briefly. It's not technically part of ksh, but is super useful if you intend to use ksh to build a ntext interface.

Some people may be familiar with the "curses" library. It is a way to manipulate and move around text on a screen, reguardless of what kind of "terminal" the user is using.

As mentioned, this is a potentially huge topic. So, I'm just going to give you a trivial example, and say "Go read the man-page on tput". Well, okay, actually, you have to read the "tput" manpage, AND either the "terminfo" or "termcap" manpage to figure out what magical 3-5 letter name to use. For example, it should tell you that "cup" is short for the "cursor_address" command. But you must use "cup", NOT "cursor_address", with tput.


tput init
tput clear
tput cup 3 2
print -n "Here is a clean screen, with these words near the top"
endline=`tput cols`
tput cup $(($endline - 2)) 
print "and now, back to you"
sleep 2


The above example clear the screen, prints the given line at a SPECIFIC place on the screen, then puts the cursor back down near the bottom of the screen for you.

PS: If you've been doing a lot of funky things with the screen, you might want to do a

tput reset
as the last thing before your shellscript exits.

Number-based menus

You dont have to build your own "choose a number" function: ksh has one already! But note that it returns the value of the line, not the number of the line.

 select word in one two three exit; do
	echo word is $word
	echo reply is $REPLY
	if [[ "$word" = "exit" ]] ; then
		break;
	fi
 done

This will print out a mini-menu like the following:
1) one
2) two
3) three
4) exit
#?

Note that this will loop between "do ... done" until you trigger a break somehow! (or until the user control-c's or whatever). So dont forget an exit condition!

Raw TCP access

Ksh88 has a built in virtual filesystem that looks like it is under /dev/tcp. You can use it to create connections to specific ports, if you know the IP address.

Here is a trivial example that just opens up a connection to an SMTP server. Note that the connection is half-duplex: You do NOT see data that you send to the other side.

#!/bin/ksh -p

MAILHOST=127.0.0.1
exec 3<>/dev/tcp/$MAILHOST/25 || exit 1

read -r BANNER <&3
echo BANNER is $BANNER
print -u3 HELO myhost.com
read -r REPLY <&3
echo REPLY is $REPLY

The output will look something like the following:

BANNER is 220 yourhost.domain.com ESMTP Sendmail 8.11.6+Sun/8.11.6; Tue, 3 Dec 2002 17:30:01 -0800 (PST)
REPLY is 250 yourhost.domain.com Hello localhost [127.0.0.1], pleased to meet you

Note that we use the "-r" flag to read. In this particular example, it is not neccessary. But in the general case, it will give you the data "raw". Be warned that if the shell cannot open the port, it will kill your entire script, with status 1, automatically

You can also dump the rest of the data waiting on the socket, to whereever you like, by doing

cat <&3 >somefile

Using arrow keys with ksh

For some reason,(older) ksh does not come with arrow key usage on the command line enabled. That being said, it is relatively easy to enable them, since it has some special hooks for the purpose.

You can cut-n-paste this into your .kshrc (if you have set ENV=$HOME/.kshrc), or directly to your prompt. Please note, however, that it presumes you have "emacs mode" enabled, otherwise it may not work properly:

set -o emacs
alias __A=`echo "\020"`     # up arrow == ^p == back a command
alias __B=`echo "\016"`     # dn arrow == ^n == down a command
alias __C=`echo "\006"`     # rt arrow == ^f == forward a character
alias __D=`echo "\002"`     # lft arrow == ^b == back a character
alias __H=`echo "\001"`     # home  == ^a == start of line
Sadly, for ksh93, the process is a bit messier, involving 'keybind' commands:
#ksh93 and later...
# put this in your kshrc
set -o emacs
typeset -A Keytable
trap 'eval "${Keytable[${.sh.edchar}]}"' KEYBD

function keybind # key action
{
	typeset key=$(print -f "%q" "$2")
	case $# in
	2)      Keytable[$1]=' .sh.edchar=${.sh.edmode}'"$key"
	;;
	1)      unset Keytable[$1]
	;;
	*)      print -u2 "Usage: $0 key [action]"
	;;
	esac
}
keybind $'\E[D' $'\002'
keybind $'\E[C' $'\006'
keybind $'\E[B' $'\016'
keybind $'\E[A' $'\020'
keybind $'\t'   $'\E\E'

Graphics and ksh

Not many people are aware of this, but there is actually a graphical version of ksh, called "dtksh". It was created as part of "CDE". Any of the modern UNIX(tm)es should come with it, in /usr/dt/bin/dtksh. If you are interested, take a look at some dtksh demos that someone else has written. And/or, you might see if you have a /usr/dt/share/examples/dtksh/ directory present on your machine.
TOP of tutorial
Next: Paranoia and good programming: Be a good programmer! Prev: Redirection and pipes
This material is copyrighted by Philip Brown