Basic Syntax
Utah uses TypeScript-like syntax to write shell scripts. This guide covers the fundamental syntax elements you'll use in every Utah script.
Variables and Constants
Variable Declarations
Utah supports three types of variable declarations:
// Mutable variable with type annotation
let userName: string = "Alice";
// Immutable constant
const appName: string = "MyApp";
// Variable with type inference (less preferred)
let count = 42;
Generated Bash Code
userName="Alice"
readonly appName="MyApp"
count="42"
Supported Types
string
- Text valuesnumber
- Numeric valuesboolean
- True/false valuesstring[]
- Arrays of stringsnumber[]
- Arrays of numbersobject
- JSON/YAML objects
String Literals and Interpolation
Basic Strings
let message: string = "Hello, World!";
Template Literals
Use template literals for string interpolation:
let name: string = "Utah";
let version: number = 1.0;
let greeting: string = "Welcome to ${name} v${version}!";
Generated bash:
name="Utah"
version="1.0"
greeting="Welcome to ${name} v${version}!"
Comments
Utah supports both single-line and multi-line comments:
// This is a single-line comment
let value: string = "Hello"; // Inline comment
Functions
Function Declaration
function functionName(param1: type, param2: type): returnType {
// Function body
return value; // if returnType is not void
}
Examples
// Function with no return value
function greet(name: string): void {
console.log("Hello, ${name}!");
}
// Function with return value
function add(a: number, b: number): number {
return a + b;
}
// Function with optional parameters (using default values)
function multiply(a: number, b: number = 1): number {
return a * b;
}
Function Generated Bash Code
greet() {
local name="$1"
echo "Hello, ${name}!"
}
add() {
local a="$1"
local b="$2"
echo $((a + b))
}
multiply() {
local a="$1"
local b="${2:-1}"
echo $((a * b))
}
Control Flow
If Statements
if (condition) {
// Code block
} else if (anotherCondition) {
// Another code block
} else {
// Default code block
}
Comparison Operators
let a: number = 5;
let b: number = 10;
let name: string = "Alice";
if (a == b) { /* equal */ }
if (a != b) { /* not equal */ }
if (a < b) { /* less than */ }
if (a > b) { /* greater than */ }
if (a <= b) { /* less than or equal */ }
if (a >= b) { /* greater than or equal */ }
// String comparisons
if (name == "Alice") { /* string equality */ }
if (name != "Bob") { /* string inequality */ }
Logical Operators
let isActive: boolean = true;
let isAdmin: boolean = false;
if (isActive && isAdmin) { /* both true */ }
if (isActive || isAdmin) { /* at least one true */ }
if (!isActive) { /* not active */ }
Switch Statements
let status: string = "active";
switch (status) {
case "active":
console.log("User is active");
break;
case "inactive":
console.log("User is inactive");
break;
default:
console.log("Unknown status");
break;
}
Loops
For Loops
Traditional C-style for loops:
for (let i: number = 0; i < 10; i++) {
console.log("Iteration: ${i}");
}
For-In Loops
Iterate over arrays:
let fruits: string[] = ["apple", "banana", "orange"];
for (let fruit: string in fruits) {
console.log("Fruit: ${fruit}");
}
While Loops
let count: number = 0;
while (count < 5) {
console.log("Count: ${count}");
count++;
}
Break Statements
for (let i: number = 0; i < 10; i++) {
if (i == 5) {
break;
}
console.log(i);
}
Arrays
Array Declaration
// String array
let names: string[] = ["Alice", "Bob", "Charlie"];
// Number array
let numbers: number[] = [1, 2, 3, 4, 5];
// Empty array
let emptyList: string[] = [];
Array Access
let fruits: string[] = ["apple", "banana", "orange"];
let first: string = fruits[0]; // "apple"
let second: string = fruits[1]; // "banana"
Array Properties and Methods
let items: string[] = ["a", "b", "c"];
let length: number = array.length(items);
let isEmpty: boolean = array.isEmpty(items);
let contains: boolean = array.contains(items, "b");
// Reverse array
let reversed: string[] = array.reverse(items);
Error Handling
Try-Catch Blocks
try {
// Code that might fail
let content: string = fs.readFile("file.txt");
console.log(content);
}
catch {
// Handle error
console.log("Failed to read file");
}
Built-in Functions
Utah provides many built-in functions organized into namespaces:
Console Functions
console.log("Message"); // Print message
console.clear(); // Clear screen
let isSudo: boolean = console.isSudo(); // Check privileges
let answer: boolean = console.promptYesNo("Continue?");
File System Functions
let exists: boolean = fs.exists("file.txt");
let content: string = fs.readFile("file.txt");
fs.writeFile("output.txt", "content");
OS Functions
let isInstalled: boolean = os.isInstalled("git");
let osType: string = os.getOS();
let version: string = os.getLinuxVersion();
Utility Functions
let randomNum: number = utility.random(1, 100);
JSON Functions
json.installDependencies(); // Ensure jq is installed
let valid: boolean = json.isValid('{"key": "value"}');
let obj: object = json.parse('{"name": "Utah"}');
let value: string = json.get(obj, ".name");
YAML Functions
yaml.installDependencies(); // Ensure yq and jq are installed
let valid: boolean = yaml.isValid("name: Utah");
let obj: object = yaml.parse("name: Utah\nversion: 1.0");
let value: string = yaml.get(obj, ".name");
Script Metadata
Script Description
Add a description to your script:
script.description("This script automates deployment tasks");
Command Line Arguments
Define and use command-line arguments:
// Define arguments
args.define("--input", "-i", "Input file path", "string", true);
args.define("--output", "-o", "Output file path", "string", false, "output.txt");
args.define("--verbose", "-v", "Enable verbose output");
// Check for help
if (args.has("--help")) {
args.showHelp();
exit(0);
}
// Get argument values
let inputFile: string = args.get("--input");
let outputFile: string = args.get("--output");
let verbose: boolean = args.has("--verbose");
Import System
Basic Import
import "utils.shx";
import "config.shx";
Import Resolution
Utah resolves imports in this order:
- Relative to current file
- Relative to script directory
- Standard library (if implemented)
Ternary Operator
let status: string = isActive ? "active" : "inactive";
let message: string = count > 0 ? "Found ${count} items" : "No items found";
Generated bash:
if [ "${isActive}" = "true" ]; then
status="active"
else
status="inactive"
fi
Exit Statements
// Exit with success
exit(0);
// Exit with error
exit(1);
// Conditional exit
if (criticalError) {
console.log("Critical error occurred");
exit(1);
}
Parallel Execution
Execute functions in parallel:
function slowTask(name: string): void {
console.log("Starting ${name}...");
// Some work here
console.log("Finished ${name}");
}
// Run tasks in parallel
parallel slowTask("Task A");
parallel slowTask("Task B");
parallel slowTask("Task C");
Best Practices
1. Always Use Type Annotations
// Good
let userName: string = "Alice";
let count: number = 42;
// Avoid
let userName = "Alice"; // Type unclear
2. Use Descriptive Names
// Good
let databaseConnectionString: string = "localhost:5432";
let maxRetryAttempts: number = 3;
// Avoid
let db: string = "localhost:5432";
let max: number = 3;
3. Handle Errors Appropriately
// Good
try {
let result: string = riskyOperation();
console.log(result);
}
catch {
console.log("Operation failed gracefully");
}
// Avoid unhandled failures
let result: string = riskyOperation(); // Might fail silently
4. Validate Dependencies
// Check before using external tools
if (!os.isInstalled("git")) {
console.log("Git is required for this script");
exit(1);
}
5. Use Constants for Fixed Values
// Good
const MAX_RETRIES: number = 3;
const CONFIG_FILE: string = "app.json";
// Less clear
let maxRetries: number = 3; // Might be changed accidentally
Syntax Highlighting
For better development experience, configure your editor for TypeScript syntax highlighting when working with .shx
files. Most editors will treat .shx
files as TypeScript files if you associate the extension.
Next Steps
Now that you understand Utah's basic syntax:
- Explore language features: Variables and Types
- Learn about functions: Function Guide
- Study control flow: Control Flow
- Discover built-ins: Built-in Functions
Common Syntax Errors
Improper Array Declaration
// Error: Incorrect array syntax
let items: Array<string> = ["a", "b"];
// Correct
let items: string[] = ["a", "b"];
Missing Semicolons
While not always required, semicolons improve clarity:
// Preferred
let name: string = "Utah";
console.log(name);
// Works but less clear
let name: string = "Utah"
console.log(name)