This package is responsible for compiling and running bash commands.
The package can be installed using the following command:
pip install git+https://github.com/OasisLMF/gerund.git
Gerund supports environment variables and chained commands out of the box. For instance, let us build a basic script that gets environment variables and prints them out with the following:
import os
print(os.environ.get('ONE'))
print(os.environ.get('TWO'))
We can call the script above run_test.py
. We can now run the following python code in another python
script:
from gerund.commands.terminal_command import TerminalCommand
env_vars = {
"ONE": "1",
"TWO": "two",
"THREE": "3"
}
test = TerminalCommand("python ./run_test.py", environment_variables=env_vars)
assert(['1', 'two'] == test.wait(capture_output=True))
what we can see is that outcomes are captured. If we set the capture_output
to False
the
outcome of the command will merely be printed out and nothing with be returned from the wait
function.
We can chain commands by passing in a list of commands like the code below:
from gerund.commands.terminal_command import TerminalCommand
env_vars = {
"ONE": "1",
"TWO": "two",
"THREE": "3"
}
test = TerminalCommand([f"python ./run_test.py", "echo 'test'"], environment_variables=env_vars)
assert(['1', 'two', 'test'] == test.wait(capture_output=True))
Here we can see that the python script has been executed first and the bash echo command have been executed afterwards and also captured.
Gerund also supports storage throughout the running lifetime of the program. Let's say we load some variables
from a profile config file or something. We can make them available to all commands and reference them
in the command using the =>
notation. An example of using local storage can be seen below:
from gerund.commands.terminal_command import TerminalCommand
from gerund.components.local_variable_storage import LocalVariableStorage
env_vars = {
"ONE": "1",
"TWO": "two",
"THREE": "3"
}
storage = LocalVariableStorage()
storage.update({
"FOUR": "four",
"SCRIPT_PATH": "./run_test.py"
})
test = TerminalCommand("python {=>SCRIPT_PATH}", environment_variables=env_vars)
assert(['1', 'two'] == test.wait(capture_output=True))
The very fact that the run_script.py
runs at all is because the TerminalCommand
understood
the {=>SCRIPT_PATH}
notation and searched the LocalVariableStorage
.
If we want to run a command on a server we can use the following parameters:
from gerund.commands.terminal_command import TerminalCommand
env_vars = {
"ONE": "1",
"TWO": "two",
"THREE": "3"
}
test = TerminalCommand('echo "test"', environment_variables=env_vars, ip_address="12345",
username="ubuntu", key="./path/to/SomeKey.pem")
test.wait()
The username
and key
parameters are optional. If we do not define the username
the default will be
"ubuntu". If we do not define a path to a key then the command will try and use the SSH agent.
Gerund handles config files when running a command. This is where we run a command that points to a config file which
has metadata and a chain of commands. For instance, we can define the following gerund.yml
config file:
output: "result.txt"
vars:
one: 1
two: two
env_vars:
three: "3"
four: four
commands:
- "echo $three"
- "echo $four"
- "echo {=>one}"
We can then our config file with the following commands:
gerund --f path/to/gerund.yml
Because we have defined the output
flat the output of the chain of commands will be captured and written to the
file defined. If the output
field is not provided the output will merely be printed out to the console. We can
also define the following optional fields:
- ip_address: the IP address of where the command will run if provided
- key: path to the SSH pem key if running on a server
- username: username for the server if IP is provided
We can also provide the following file formats:
{
"output": "result.txt",
"vars": {
"one": 1,
"two": "two"
},
"env_vars": {
"three": "3",
"four": "four"
},
"commands": [
"echo $three",
"echo $four",
"echo {=>one}"
]
}
[meta]
output=result.txt
[vars]
one=1
two=two
[env_vars]
three=3
four=four
[commands]
echo $three
echo $four
echo {=>one}
Gerund supports bash scripts. You can either pass in a list of commands that will be written as a bash script, or you
can pass in a path to a bash script to be run. If the ip_address
is passed in the bash script will be run on the
server belonging to the ip_address
. For instance, let us say that he has the following bash script:
#!/usr/bin/env bash
SCRIPTPATH="$( cd "$(dirname "$0")" ; pwd -P )"
cd $SCRIPTPATH
ls
echo $ONE
if [ -d "/path/to/dir" ]
then
echo "Directory /path/to/dir exists"
else
echo "Directory /path/to/dir does not exist"
fi
we can point to this bash script and run it with the following code:
from gerund.commands.bash_script import BashScript
from typing import Optional, List
example = BashScript(path="./path/to/script.sh")
outcome: Optional[List[str]] = example.wait()
The command version would take the following form:
from gerund.commands.bash_script import BashScript
from typing import Optional, List
commands = [
'#!/usr/bin/env bash',
'',
'SCRIPTPATH="$( cd "$(dirname "$0")" ; pwd -P )"',
'cd $SCRIPTPATH',
'',
'ls',
'echo $ONE',
'',
'if [ -d "/path/to/dir" ]',
'then',
' echo "Directory /path/to/dir exists"',
'else',
' echo "Directory /path/to/dir does not exist"',
'fi',
'',
''
]
example = BashScript(commands=commands)
outcome: Optional[List[str]] = example.wait()
The BashScript
constructor supports the following inputs:
- commands:
(Optional[List[str]])
each element is a line in a bash script - path:
(Optional[str])
path to bash script to be written or read - environment_variables:
(EnvVars)
environment variables to be applied when running bash script - ip_address:
(Optional[str])
IP address of the server to run the bash script if running on server - key:
(Optional[str])
path to pem key if needed to be run on server - username:
(str)
the username of the server which has a default of "ubuntu" - capture_output:
(bool)
for the output to be captured with a default of False