---
title: "Shell (Bash) Scripting"
order: 3
---

Shell (_Bash/Sh_) is the standard for automating configuration on Linux servers. Otter was designed to seamlessly integrate with Shell scripts -- whether that means running your existing scripts across dozens of servers, leveraging scripts built by the community, or a custom combination of both.

## Executing Inline
If you just want to execute a short Shell script, or if you want to use OtterScript variable replacement to build out your script, you can use the `ShExec` operation:

#### Example: Single line create folder
```OtterScript
ShExec mkdir "/home/user/temp";
```

#### Example: Single line create folder using an OtterScript variable
```OtterScript
set $temp_folder_path = /home/user/temp;
ShExec mkdir "$temp_folder_path";
```

#### Example: Multi line create folder
```OtterScript
set $temp_folder_path = /home/user/temp;
ShExec >>
echo "Creating directory $temp_folder_path"
mkdir $temp_folder_path
>>;
```

## Executing Scripts
Shell scripts can be run directly, as a job template, or in OtterScript using the `SHCall` operation. If you use augmented help, you'll get descriptions for script arguments when running the script, creating a job template, and when editing OtterScript in visual mode.

_CreateTempFolder.sh_ Example:
```bash
echo "Creating directory /home/user/temp"
mkdir "/home/user/temp"
```

OtterScript Example:
```otterscript
SHCall CreateTempFolder.sh;
```

### Adding Arguments/Parameters
Arguments can be passed to `ShCall` by specifying them in the `Arguments` property.  These arguments can then be accessed in the script using `$1, $2, ...$n`.

_CreateTempFolder.sh_ Example:
```bash
echo "Creating directory $1"
mkdir "$1"
```

OtterScript Example:
```otterscript
SHCall CreateTempFolder.sh
(
   Arguments: '"/home/user/temp"'
);
```

### Augmented Help with Otter
[Augmented help](/docs/otter/scripting-in-otter/otter-scripting-augmented-help) is an Inedo-specific commenting format that describes what the script does, how to use the script's arguments (input and output), and adds a custom UI around executing the shell script. 

:::(Info) (NOTE:)
When mapping AhParameters as output variables to OtterScript Variables:
- You must omit the `$` character of the OtterScript variable that is being mapped
- Scripts cannot include `exit #` or `return #`
:::

#### Example: Send an email when Disk usage is high
_DiskUsagePercentage.sh_ Script:
```bash
#!/bin/bash
# AhDescription: This script will find the disk usage percentage
# AhParameter: path_check
# AhParameter: percent_used (output)

echo "Finding disk usage percentage for $path_check..."
percent_used=$(df --output=pcent $path_check | awk 'NR==2{ print $1 }')
```

OtterScript:
```otterscript
set $disk_path = /dev/sdb;

SHCall DiskUsagePercentage.sh
(
    Parameters: %(path_check: $disk_path, percent_used: percentUsed)
);

if $Compare($TrimEnd($percentUsed, `%), >, 80, true) == true
{
    InedoCore::Send-Email
    (
        To: support@mycompany.com,
        Subject: Disk Almost Full,
        Text: Disk $disk_path is currently using $percentUsed of its available storage capacity.
    );
}
```

## Drift Detection & Remediation

### Drift Detection
Otter can use your existing Shell scripts to verify server configuration by using a special operation called `SHVerify2`. This leverages augmented help comment-headers to help instruct Otter on how to verify the desired configuration.

:::(Info)
Currently, this is a preview feature.  In Otter v2022+, this operation will be called `SHVerify`.
:::

Use `SHVerify2` to enable detecting invalid server configuration with a Shell script.

#### Example: Shell Script to Verify that a Folder Exists

```bash
#!/bin/bash
# AhDescription: Verifies that a folder exists.
# 
# AhParameter: folderPath: full path to verify
# AhConfigKey: $folderPath
# AhDesiredValue: True
# AhCurrentValue: $folderExists

if [ -d "$folderPath" ]
then
   folderExists=True
else
   folderExists=False
fi
```

### Remediation
In addition to verifying the configuration of your servers, Otter can use your existing Shell scripts to reconfigure your servers into your desired state using an operation called `SHEnsure2`.

:::(Info)
Currently, this is a preview feature.  In Otter v2022+, the current `SHEnusre` will become `SHEnsureScripts` and `SHEnsure2` will become `SHEnsure`.
:::

You can use `SHEnsure2 ` to perform verification as with `SHVerify2` but also add the ability to correct any detected configuration problems.

#### Example: Shell Script to Ensure that a Folder Exists

```bash
#!/bin/bash
# AhDescription: Verifies that a folder exists.
# 
# AhParameter: folderPath: full path to verify
# AHExecMode: $execMode
# AhConfigKey: $folderPath
# AhDesiredValue: True
# AhCurrentValue: $folderExists

echo "Execution mode: $execMode"
echo "Folder path: $folderPath"

if [ "$execMode"  = "Collect" ]
then
   if [ -d "$folderPath" ]
   then
      folderExists=True
   else
      folderExists=False
   fi
else
   mkdir "$folderPath"
   folderExists=True
fi
```

## Technical Implementation
Otter will first write your script to a temporary directory, then it will use the Linux command line to execute your scripts via `./<<file-name>> <<arguments>>`, and will then remove the temporary file after. 

When using [augmented help](/docs/otter/scripting-in-otter/otter-scripting-augmented-help), there are a few differences in the execution.  
- AhParameters are defaulted to an "input" usage and will be prepended to the beginning of the temporary script so they can be used by name (e.g. `$dir1` in the script).
- AhParameters with the "args" usage will be passed in order via the command line arguments.  For example, if you have parameters `$dir1` and `$dir2`, these will be passed to the script as `./example.sh $dir1 $dir2`.  
- When including AhParameters with the "output" usage type, the Shell script will be wrapped in a function named `AhScriptWrapper` so variables can be exported.  This prevents the use of `return` and `exit` from within the script.  Instead, use another "output" AhParameter and handle it using OtterScript.

## FAQ

### Why are my arguments out of order?
By default, Otter will pass the AhParameters with a usage type of "args" in the order specified as arguments to the shell script.  If these arguments are passed in using the wrong order, you will need to specify a custom `AhArgumentFormat`.  

Example: `# AhArgsFormat: $ip_address $subnet_mask dns_address`
