5.8. Command Substitutions¶
Currently, the ability to parameterize strings to have ConsoleUser substitute values at runtime is only used by the CommandShell Markov Brain.
ConsoleUser supports command substitution in that strings it uses can
include sequences that cause a value to be retrieved from elsewhere and
used in that spot. Without this ability every string is treated as a
literal set of instructions to type. For example, when doing tasks in
the _CommandShell module ConsoleUser will execute each string as it is
passed to it. So the CommandShellBrain would need to load a different
command to do host www.zulu.isp
and host web.susilva.isp
.
Using command substitution we can have ConsoleUser “know” the host
command and substitute names from other parameters at runtime. To do
this we use square brackets to set off tokens that indicate where the
expanded value should come from. If, for example, ConsoleUser has a
config value with the name lookupSites
that contains a list with
both of the sites used above, we could specify a command to use them as
host [lookupSites]
. When that command is selected the
lookupSites
name triggers ConsoleUser to lookup a value to put in
that spot.
The way the values are looked up is to first see if the brain instance
itself has an instance value matching that name. If it does not, check
if the _User instance has one, or if its _UserConfig has it. If any of
those lookups find a matching value ConsoleUser will derive the string
to type from it. To do this, ConsoleUser will see if the value is a
basic string, like the user’s loginName field generally is for example.
If it is, that value is used. If, instead, the value is a list, or
similar sequence, a random value will be selected from it (by calling
random.choice
on it). If it is neither a string nor a list,
ConsoleUser will treat it as one of its Chooser instances which
typically consume a CDF Line. In that case the next choice will
be retrieved from the Chooser and that will be used.
If the name is not found or the value cannot be resolved the original bracketed string will be left in place.
For example, if a user has the following as part of their
CommandShell.conf
:
CommandShellTasks = 0.5 echo Random Task: [_commands], 0.75 echo [loginName] 1.0 netstat
and the line loginName = consoleUser1
in the user.conf
file
then when the user begins it will load the CommandShellTasks
line
into the module brain’s self._commands
variable that is a
CDFChooser instance, and the User instance will have its config
variable set loginName
to consoleUser1
. When the chooser
selects the first option it will then run the command that begins
echo Random Task
and then it will call the next_choice on the
module brain’s _commands
chooser instance. Similarly, if it picks
the second command it will end up typing the command
echo consoleUser1
.
To know, or add to, the variables that are available to reference in the substitution block might require inspecting the code. For example, CommandShellBrain includes the following lines:
self._commands = CDFChooser()
self._commands.set_logger(self.logger)
self._commands.parse_line(self.config.CommandShellTasks)
which is how we know there is a _commands
variable that we could
reference in the config line above. All keys defined the conf files
loaded by a _User will end up available as raw strings in the
user.config
or self.config
(same object) variables, but if the
value should be a list or other selecting instance like the CDFChooser
above, code to parse the value might have to be added.
For example, if we want to define a list of values that could be
selected for inclusion in a command, say a list of domains that we may
use for commands like host
or dig
or ping
we might want to
add the following lines to CommandShellBrain’s __init__
method:
self._domains = []
if self.config.commandDomains:
self._domains = [x.strip() for x in self.commandDomains.split(',')]
then we could use the following in the config file:
commandDomains = www.zulu.isp, web.susilva.isp, another.host.com
commandShellTasks = 0.5 ping [_domains], 1.0 dig [_domains]
It’s also worth remembering that the keys in the config file, e.g.,
commandDomains
are case insensitive so CommandDomains
would
also match.