Skip to main content

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 values
  • number - Numeric values
  • boolean - True/false values
  • string[] - Arrays of strings
  • number[] - Arrays of numbers
  • object - 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:

  1. Relative to current file
  2. Relative to script directory
  3. 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:

  1. Explore language features: Variables and Types
  2. Learn about functions: Function Guide
  3. Study control flow: Control Flow
  4. 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)