Usage and examples of Sequencer scripts
The basic way of using the sequencer is by typing sequencer commands in a
terminal window.
The sequencer commands are exactely like any other UNIX command in the
way that they
are executed and exists as processes. As they get executed by the shell
(C shell by default), all aspects of job control, shell syntax etc. applies
to the sequencer commands as they do to any other UNIX command.
They can be put in the background, using "Ctrl-Z, bg" or using "&" after the
command. An example of this is the "expose" command. If given normally, i.e.
executing in the foreground, the command will not return until the image is
read out and stored on disk. You can execute the command in the background
("expose &") and get the command prompt back immediately. In this case you
can use the "about" command to about the on-going exposure.
These comments are only highlights of a small number of possibilities available.
The real "sequencer manual" is, in fact, a manual of the UNIX C shell (or the
shell of your choice if using a script).
There is great flexibility when writing scripts for the sequencer. As the
normal UNIX tcsh shell is used, the syntax is well documented elsewhere
Click here for a manual in C shell script writing
It is also possible to use BASH for making scripts, in any case the full command
names must be used (e.g. alfosc.xbin). The full command names for the
different command groups can be found in the command reference in the
header for the command groups (i.e. BIAS, instrument, TCS, etc.)
You may copy any instrument script to your own directory for editing, for instance doing:
cp ~staff/alfosc.polspecwin my.polspecwin
There are some basic rules that must be followed to get the correct behaviour.
- The first line of the script MUST be
#!/bin/tcsh
or
#!/bin/bash
in the case you want to use BASH.
- Before you can use your script, you have to make it executable with the
command
chmod +x my_script
- Commands (in this case sequencer commands) can be executed in the
background putting a '&' after the command. In this case,
the script will immediately continue to the next command in the script.
- The script can use parameters given on the command line. These are
accessible in the variables $1, $2 etc.
In the script executed like this:
my_script var1 var2
var1 will be available as $1 and var2 as
$2.
- Your script can (and should if it is complicated) log informative
messages to the talker (and thus to the user), using the logger
command.
Three levels of logging can be used - DEBUG, NOTE and ERROR. DEBUG is
used for functionality debugging and can only be seen when this level
has been enabled in the Talker. NOTE is the normal way of logging
informative messages. ERROR is only used for errors produced by the
programme/script. The ERROR messages will appear in red in the Talker.
Here is how to use it:
/usr/bin/logger -p local0.debug -t "scriptname" "[NOTE]: My note"
for normal log messages
/usr/bin/logger -p local0.debug -t "scriptname" "[DEBUG]: My note"
for debug log messages
/usr/bin/logger -p local0.debug -t "scriptname" "[ERROR]: My note"
for error log messages
, where "scriptname" must be an informative name of your script.
Alternatively, '$0' can be used as scriptname to use the current filename.
The square brackets, the colon and the following space must be there.
We strongly advice to notify the talker upon start and end of script execution:
logger -p local0.debug -t "$0" "[NOTE]: Script started as $0 $*"
... the script ...
logger -p local0.debug -t "$0" "[NOTE]: Script ended successfully"
The '$0' will echo the script name, and '$*' will echo the parameters which the
script was called with.
An example:
An ALFOSC script that will make a 300 second exposure with a teloffset of variable size
(to be given on the command line) in 3 filters can be written like this:
#!/bin/tcsh
logger -p local0.debug -t "$0" "[NOTE]: Script started as $0 $*"
set xoffset = $1
set yoffset = $2
set filters = "1 2 3"
foreach filter ($filters)
alfoscinst.filter $filter
alfosc.expose 300
alfosc.teloffset $xoffset $yoffset
end
logger -p local0.debug -t "$0" "[NOTE]: Script ended successfully"
exit
This script will then be used like
myscript 10.0 10.0
The commands that moves an element (a filter, grism, arm etc.etc) will
not complete until this movement has been made. This means that in the
script above, the 'expose' command will not start until the filter has
arrived at the commanded position and the 'teloffset' command will not
start until the exposure (and readout) has finished.
Dealing with error
Any program that you execute from inside a script may end because of an error.
The way programs tell you about errors is through status codes.
This status code is a number from 0 to 255, that you can find in the
$? variable. This variable will always contain the status code for
the latest program that has finished running before testing for
said code. Note that This Doesn't Apply to Programs That Have Been
Running in the Background. It's difficult to track the return code for
those programs, and thus you will never get it from them.
A value of 0 means "no error". Any other value means "something happened",
and will be considered an error.
Of course, having a variable with a numeric value defining if there was an
error (or not) in the previous command, allows us to test for errors
using an "if" construct.
Shell script interpreters may react to the errors automatically, or not.
This behaviour is controlled using the "-e" modifier in the first
line of the script, like this:
#!/bin/tcsh -e
If this "-e" is specified, the script will abort
as soon as a program returns an error code if the error
is not captured somehow. If the "-e" modifier is not specified,
then you're responsible for all the error handling.
The following explanation on capturing and treating errors assume you've
specified the -e. As it's been said, the script will abort if
the last executed program (that is not in the background) exits
with an error code. There are a couple of subtleties when it comes to
defining "the last executed program". For example, in here:
#!/bin/csh -e
echo "This line is executed"
# This is a program that returns an error
faulty_program
echo "This line is never executed"
In this case it's quite clear what happens, but there are other modes where
certain subtleties determine which code we get, like this:
#!/bin/csh -e
echo "This line is executed"
faulty_program | non_faulty_program
echo "This line *is* executed too"
What happened here? When there's a sequence of programs, only the
last one to be executed is taken into account. In this case, we had a sequence
of piped programs, and the only return code that the shell cares about is the
one from the last program in the pipe. The first one in line failed, but the
second didn't, and so the script continued happily. This is something we need
to have in mind, because errors can slip without us noticing, while we
thought the script was going to fail in case something happens.
Other sequences are the ones where programs are separated by || or
by &&. Those are rather useful when controlling errors. And
they work the following way:
- When two programs are separated by || (two vertical bars), the
second one will be executed only if the first one fails.
You could interpret a line saying program1 || program2
as if it reads "do this thing and, if it fails do this other".
Note that if the first program doesn't fail, the second one never
executes, and the shell considers this as a non-error situation.
If the first program fails, the second one is executed, and it will be
its return code the one that the shell takes into account to figure out
if it needs to abort or not.
- When two programs are separated by &&, the second one
will be executed only if the first one returned without
error.
Now, if the first program fails, the second won't execute, and the
shell will get the error code from the first program, because
it was the last one to be executed. Then, this is an error and
the script will abort.
By using || and &&, we can easily control the
execution of certain programs, and what to do in case of failure (or success).
An example use is logging and quit after a critical error, like this:
# If the following fails, the rest of the script shouldn't work
alfosc.exp 5 || ( logger -p local0.debug -t "myscript" "[ERROR]: Couldn't expose. Aborting"; exit 1 )
|