1. What's wrong with the following code:
#!/usr/bin/ksh
function print_postscript
{
if $HAS_PS
then
# just spool output
${PRT_CMD[*]} "$1"
else
gs -q -sDEVICE=$GS_DRIVER -dNOPAUSE -sOutputFile= "$1" quit.ps |
${PRT_CMD[*]}
fi
}
function print_pcl
{
...
}
# restrict PATH
export PATH=/opt/gs5.10/bin:/opt/tfware/bin:/opt/lprNG/bin
alias -x false='let 0'
[[ -f /opt/tfware/printers/$1 ]] && . /opt/tfware/printers/$1
# this loads definition of printer capabilities into following
# vars:
# HAS_PCL=(true or false)
# HAS_PS=(true or false)
# GS_DRIVER=(name of ghostscript driver)
# PRT_CMD=(array of print directives directing output at either lp or lpr)
# PRT_CMD contains real name of printer i.e. passthru@prt2756e
# QCMD=(array of print directives to get q info)
case $2 in
*.ps) print_postscript "$2";;
*.pcl) print_pcl "$2";;
esac
...
ANSWER:
A little background first: I am using Applix Anyware to implement
a browser accessible "Websheet" application. Anyware sets its
environment from a file called aaenv, into which I had placed:
PATH=/path/to/bin:/path/to/bin:$PATH
Unfortunately, this file is not processed by a shell so $PATH
was taken literally. When the user tried to print which calls a
version of the above shell, (which did not contain the alias
for false, since that is builtin but was shown for doco purposes),
it failed because false couldn't be found because the PATH didn't
contain /usr/bin. The alias for false wasn't recognized because
alias substitution takes place before variable substitution.
2. I want to send formatting sequences to the terminal. The system
has "tput", which uses terminfo. Processing terminfo sequences
is time consuming, so I want to call "tput" as few times as possible.
Tput has a "-S" option that allows it to take a stream of sequences,
one per line, and send them to stdout. So:
tput -S <<!
home
clear
!
will home the cursor and clear the screen. The sequence:
tput <<!
home
clear
cup 10 10
!
will home the cursor, clear the screen, and position the cursor
at 10 10. I discover by experimentation that tput uses
setbuf(stdout,NULL), so that stdout is continually flushed.
It also does not terminate the sequences with newlines.
I decide to run tput -S as a coprocess:
tput -S |&
To send sequences I issue:
print -p cup 0 0
However, when I do:
read -p cup
my script hangs. Why?
So I change methodology - I call:
tput -S >/dev/tty |&
Now I:
print -p cup 0 0
print "Welcome to the Systems Admin Training Program"
print -p cup 3 0
print "Select Option:"
...
This fails spectacularly. Why?
Is there a nasty solution (using tput) available?
ANSWER:
A classic race condition. Normally when you print to a co-process
you immediately read from the coprocess. That gives up control of
the writing process and allows the reading process - previously
blocked on its read - to gain control. In my case, I wound up
printing all the ordinary text followed by the screen formatting
sequences.
The nasty solution - since I was only writing to hpterms, xterms and
dtterms, I found sequences that converted to newlines - ind for
hpterm and xterm and cud1 for dtterm, then I
case $TERM in
+(hp|x)term) newline=ind;;
dtterm)newline=cud1;;
esac
print -p "cup 0 0\n$newline"
read -p CUP
3. Without using any program external to ksh, or permanently
modifying the environment, or using any form of do loop,
and using a one line script, print out the elements of
array A one per line. Hint: the answer is just 31 chars
long.
ANSWER:
This can be done by changing the IFS. The first char in the IFS
is the OFS. However, it must be set in the current shell
environment. While:
command | while IFS= read line
works fine,
IFS=: print "${path[*]}"
does not, since the shell is expanding "${path[*]}", not the
print command. So a subshell is needed. The last remaining
trick is to get a newline in the IFS. Well, there already is one -
it's the third character, so stripping off the first two chars
ought to do the trick. My original answer was:
(IFS=${IFS#??};print "${A[*]}")
but as was pointed out to me, this fails if A[0] begins with a
"-" or A contains escape sequences "\n". So the correct answer
is:
(IFS=${IFS#??};print -r - "${A[*]}")
and the hint needs to be changed from 31 chars to 36.
4. What does the following script do - how would you call it:
#!/usr/bin/ksh
awk '$0~r {x=l+1}x&&x--' "$@"
ANSWER:
Think of this as a script named context. If you call it with:
context r='some regular expression' l=lines_of_context file1 file2 ...filen
then it will find every line matching the regular expression and print
it with AT LEAST l lines of following context. If the expression
occurs more than once in l lines, the context will extend to l lines
past the last occurrance. But because awk processes the command
line in order, what happens when I:
context r='somere' l=3 file1 r='different re' file2
'somere will be applied against file1 and 'different re' against
file2
Thanks to all who played.
--
Dan Mercer
dame...@uswest.net
Opinions expressed herein are my own and may not represent those of my employer.