Skip to main content

System Functions

Utah provides system-level functions for process management, environment interaction, and system administration.

System Information

Platform Detection

// Get operating system
let os: string = system.platform();

// Get architecture
let arch: string = system.architecture();

// Get hostname
let hostname: string = system.hostname();

// Get current user
let user: string = system.user();

Environment Variables

// Get environment variable
let path: string = system.env("PATH");

// Set environment variable
system.setEnv("MY_VAR", "value");

// Check if variable exists
let exists: boolean = system.hasEnv("HOME");

Process Management

// Get process ID
let pid: number = system.pid();

// Execute command
let result: string = system.execute("ls -la");

// Start a process in the background and get its PID
let backgroundPid: number = process.start("echo 'Hello World'");

// Check if a process is running
let isRunning: boolean = process.isRunning(backgroundPid);
console.log("Process running: " + isRunning);

// Check if system init process is running (always true)
let initRunning: boolean = process.isRunning(1);

// Wait for a process to complete and get its exit code
let buildPid: number = process.start("make build");
let exitCode: number = process.waitForExit(buildPid);
if (exitCode == 0) {
console.log("Build succeeded");
} else {
console.log("Build failed with exit code: " + exitCode);
}

// Wait with timeout (milliseconds)
let deployPid: number = process.start("deploy.sh");
let result: number = process.waitForExit(deployPid, 30000); // 30 second timeout
if (result == -1) {
console.log("Deployment timed out");
} else if (result == 0) {
console.log("Deployment completed successfully");
} else {
console.log("Deployment failed");
}

// Process monitoring workflow
let longRunningPid: number = process.start("sleep 30");
while (process.isRunning(longRunningPid)) {
console.log("Process still running...");
// Do other work or sleep for a bit
}
console.log("Process finished");

// Start process with working directory
let pid1: number = process.start("pwd", { cwd: "/tmp" });

// Start process with input redirection
let pid2: number = process.start("cat", { input: "/etc/hostname" });

// Start process with output redirection
let pid3: number = process.start("date", { output: "/tmp/timestamp.txt" });

// Start process with error redirection
let pid4: number = process.start("ls /nonexistent", { error: "/tmp/errors.log" });

// Start process with all options
let pid5: number = process.start("sort", {
cwd: "/tmp",
input: "/etc/passwd",
output: "/tmp/sorted.txt",
error: "/tmp/sort_errors.log"
});

// Execute with error handling
try {
let output: string = system.execute("some-command");
} catch (error) {
console.log("Command failed");
}

Advanced Process Management

Waiting for Process Completion

The process.waitForExit() function allows you to wait for a background process to complete and retrieve its exit code:

// Basic usage - wait indefinitely
let buildPid: number = process.start("npm run build");
let exitCode: number = process.waitForExit(buildPid);

if (exitCode == 0) {
console.log("Build succeeded");
} else {
console.log("Build failed with exit code: " + exitCode);
}

// Wait with timeout (in milliseconds)
let testPid: number = process.start("npm test");
let result: number = process.waitForExit(testPid, 120000); // 2 minute timeout

if (result == -1) {
console.log("Tests timed out after 2 minutes");
} else if (result == 0) {
console.log("Tests passed");
} else {
console.log("Tests failed with exit code: " + result);
}

// Sequential workflow example
function deployApplication(): void {
// Step 1: Build
console.log("Building application...");
let buildPid: number = process.start("npm run build");
let buildResult: number = process.waitForExit(buildPid, 300000); // 5 minute timeout

if (buildResult == -1) {
console.log("Build timed out");
exit(1);
} else if (buildResult != 0) {
console.log("Build failed");
exit(1);
}

// Step 2: Test
console.log("Running tests...");
let testPid: number = process.start("npm test");
let testResult: number = process.waitForExit(testPid, 600000); // 10 minute timeout

if (testResult == -1) {
console.log("Tests timed out");
exit(1);
} else if (testResult != 0) {
console.log("Tests failed");
exit(1);
}

// Step 3: Deploy
console.log("Deploying application...");
let deployPid: number = process.start("kubectl apply -f deployment.yaml");
let deployResult: number = process.waitForExit(deployPid, 180000); // 3 minute timeout

if (deployResult == 0) {
console.log("Deployment completed successfully");
} else {
console.log("Deployment failed");
exit(1);
}
}

// Parallel execution with synchronization
let task1Pid: number = process.start("process-large-file-1.sh");
let task2Pid: number = process.start("process-large-file-2.sh");
let task3Pid: number = process.start("process-large-file-3.sh");

// Wait for all tasks to complete
let result1: number = process.waitForExit(task1Pid, 1800000); // 30 minute timeout
let result2: number = process.waitForExit(task2Pid, 1800000);
let result3: number = process.waitForExit(task3Pid, 1800000);

if (result1 == 0 && result2 == 0 && result3 == 0) {
console.log("All parallel tasks completed successfully");
} else {
console.log("Some tasks failed or timed out");
if (result1 != 0) console.log("Task 1 failed/timed out");
if (result2 != 0) console.log("Task 2 failed/timed out");
if (result3 != 0) console.log("Task 3 failed/timed out");
}

Process Management Features

  • Exit Code Retrieval: Get the actual exit code from completed processes
  • Timeout Support: Prevent indefinite waiting with configurable timeouts
  • Non-blocking: Continue script execution while waiting for processes
  • Cross-platform: Works on all Unix-like systems (Linux, macOS, BSD)
  • Resource Efficient: Uses 100ms polling interval for responsive yet efficient monitoring

Return Values

  • 0-255: Normal process exit codes (0 typically means success)
  • -1: Timeout occurred (process was still running when timeout expired)

Terminating Processes

The process.kill() function allows you to terminate running processes using different signals:

// Basic usage - terminate with default SIGTERM signal
let pid: number = process.start("sleep 60");
let killed: boolean = process.kill(pid);

if (killed) {
console.log("Process terminated successfully");
} else {
console.log("Failed to terminate process");
}

// Force kill with SIGKILL signal
let longRunningPid: number = process.start("infinite-loop.sh");
let forceKilled: boolean = process.kill(longRunningPid, "SIGKILL");

// Using numeric signal values
let anotherPid: number = process.start("background-task.sh");
let terminated: boolean = process.kill(anotherPid, 9); // SIGKILL

// Graceful shutdown with fallback
let servicePid: number = process.start("my-service.sh");

// Try graceful shutdown first
let gracefulShutdown: boolean = process.kill(servicePid, "SIGTERM");
if (!gracefulShutdown || process.isRunning(servicePid)) {
console.log("Graceful shutdown failed, forcing termination");
process.kill(servicePid, "SIGKILL");
}

// Process management workflow
function manageWorkflow(): void {
let workers: number[] = [];

// Start multiple worker processes
for (let i: number = 0; i < 3; i++) {
let workerPid: number = process.start("worker.sh " + i);
workers.push(workerPid);
}

// Terminate all workers on completion
for (let pid of workers) {
if (process.isRunning(pid)) {
process.kill(pid, "SIGTERM");
}
}
}

Supported Signals

  • SIGTERM (default): Graceful termination request
  • SIGKILL: Force immediate termination (cannot be ignored)
  • SIGINT: Interrupt signal (Ctrl+C equivalent)
  • SIGHUP: Hangup signal (often used for config reload)
  • SIGUSR1, SIGUSR2: User-defined signals
  • Numeric values: Direct signal numbers (e.g., 9 for SIGKILL, 15 for SIGTERM)

Process Kill Features

  • Signal Support: Send different termination signals to processes
  • Boolean Return: Returns true if kill signal was sent successfully, false otherwise
  • Cross-platform: Works on all Unix-like systems with standard signal support
  • Safe Operation: Handles invalid PIDs gracefully without crashing
  • Variable Support: Use variables for both PID and signal parameters

File System Operations

Path Operations

// Get current directory
let cwd: string = system.cwd();

// Change directory
system.cd("/path/to/directory");

// Get home directory
let home: string = system.home();

// Get temp directory
let temp: string = system.temp();

File Operations

// Check if file exists
let exists: boolean = system.fileExists("/path/to/file");

// Check if directory exists
let dirExists: boolean = system.dirExists("/path/to/dir");

// Create directory
system.mkdir("/path/to/new/dir");

// Remove file
system.remove("/path/to/file");

Generated Bash

System functions compile to appropriate bash commands:

# Platform detection
os=$(uname -s)

# Environment variables
path="$PATH"
export MY_VAR="value"

# Process management
pid=$$
result=$(ls -la)

# Background process execution with process.start()
backgroundPid=$(echo 'Hello World' &; echo $!)

# Process with working directory
pid1=$((cd "/tmp" && pwd &); echo $!)

# Process with input redirection
pid2=$(cat < "/etc/hostname" &; echo $!)

# Process with output redirection
pid3=$(date > "/tmp/timestamp.txt" &; echo $!)

# Process with error redirection
pid4=$(ls /nonexistent 2> "/tmp/errors.log" &; echo $!)

# Process with all options
pid5=$((cd "/tmp" && sort < "/etc/passwd" > "/tmp/sorted.txt" 2> "/tmp/sort_errors.log" &); echo $!)

# File system operations
cwd=$(pwd)
cd "/path/to/directory"
home="$HOME"

Use Cases

  • System administration scripts
  • Environment setup and configuration
  • Process monitoring and management
  • File system operations
  • Cross-platform compatibility

System Resource Monitoring

CPU Count

// Get the number of CPU cores
let cores: number = system.cpuCount();
console.log("CPU cores: ${cores}");

Total Memory

// Get total system memory in MB
let totalMem: number = system.memoryTotal();
console.log("Total memory: ${totalMem} MB");

Memory Usage

// Get current memory usage as a percentage (0-100)
let memUsage: number = system.memoryUsage();
console.log("Memory usage: ${memUsage}%");

Generated Bash

# CPU count (cross-platform: Linux + macOS)
cores=$(nproc 2>/dev/null || sysctl -n hw.ncpu 2>/dev/null || echo "1")

# Total memory in MB
totalMem=$(free -m 2>/dev/null | awk 'NR==2 {print $2}' || sysctl -n hw.memsize 2>/dev/null | awk '{printf("%d", $1/1024/1024)}' || echo "0")

# Memory usage percentage
memUsage=$(free 2>/dev/null | awk 'NR==2 {printf("%d", ($3/$2)*100)}' || echo "0")

Process Information

Utah provides functions to inspect the current process.

process.id()

Returns the current process ID.

let pid: number = process.id();
console.log("Process ID: ${pid}");

process.cpu()

Returns the CPU usage percentage of the current process (rounded to nearest integer).

let cpuUsage: number = process.cpu();
console.log("CPU Usage: ${cpuUsage}%");

process.memory()

Returns the memory usage percentage of the current process (rounded to nearest integer).

let memUsage: number = process.memory();
console.log("Memory Usage: ${memUsage}%");

process.elapsedTime()

Returns the elapsed time since the process started.

let elapsedTime: string = process.elapsedTime();
console.log("Elapsed Time: ${elapsedTime}");

process.command()

Returns the command line used to start the current process.

let command: string = process.command();
console.log("Command: ${command}");

process.status()

Returns the process status code (e.g., S for sleeping, R for running).

let status: string = process.status();
console.log("Status: ${status}");

Generated Bash

# Process ID
pid=$(ps -o pid -p $$ --no-headers | tr -d ' ')

# CPU usage (rounded)
cpuUsage=$(ps -o pcpu -p $$ --no-headers | tr -d ' ' | awk '{printf("%d", $1 + 0.5)}')

# Memory usage (rounded)
memUsage=$(ps -o pmem -p $$ --no-headers | tr -d ' ' | awk '{printf("%d", $1 + 0.5)}')

# Elapsed time
elapsedTime=$(ps -o etime -p $$ --no-headers | tr -d ' ')

# Command line
command=$(ps -o cmd= -p $$)

# Process status
status=$(ps -o stat= -p $$)

Timer Functions

Utah provides timer functions for measuring execution time in milliseconds.

timer.start()

Starts the timer by recording the current timestamp.

timer.start();

timer.stop()

Stops the timer and returns the elapsed time in milliseconds since timer.start() was called.

timer.start();

// ... do some work ...

let elapsed: number = timer.stop();
console.log("Elapsed: ${elapsed} ms");

timer.current()

Returns the number of milliseconds elapsed since timer.start() was called, without stopping the timer.

timer.start();

// ... do some work ...
let soFar: number = timer.current();
console.log("So far: ${soFar} ms");

// ... do more work ...
let total: number = timer.stop();
console.log("Total: ${total} ms");

Generated Bash

# timer.start()
_utah_timer_start=$(date +%s%3N)

# timer.stop() — returns elapsed ms
_utah_timer_end=$(date +%s%3N)
elapsed=$((_utah_timer_end - _utah_timer_start))

# timer.current() — returns elapsed ms without stopping
soFar=$(( $(date +%s%3N) - _utah_timer_start ))

Scheduler Functions

For cron-based job scheduling, see the dedicated Scheduler documentation.