Skip to main content

Console Functions

The console namespace provides functions for user interaction, output formatting, and terminal control. These functions handle input/output operations and enhance script usability.

Output Functions

console.log()

Print messages to standard output with automatic newline:

console.log("Hello, World!");
console.log("Current user: ${USER}");

let count: number = 42;
console.log("Processing ${count} items");

Generated Bash:

echo "Hello, World!"
echo "Current user: ${USER}"
count=42
echo "Processing ${count} items"

console.clear()

Clear the terminal screen:

console.clear();
console.log("Screen cleared - starting fresh");

Generated Bash:

clear
echo "Screen cleared - starting fresh"

Test Coverage:

  • File: tests/positive_fixtures/console_clear.shx
  • Tests terminal clearing functionality

Interactive Functions

console.prompt()

Prompt user for input with a message:

let name: string = console.prompt("Enter your name: ");
console.log("Hello, ${name}!");

let age: string = console.prompt("Enter your age: ");
console.log("You are ${age} years old");

Generated Bash:

read -p "Enter your name: " name
echo "Hello, ${name}!"
read -p "Enter your age: " age
echo "You are ${age} years old"

console.promptYesNo()

Prompt user for yes/no confirmation:

let shouldContinue: boolean = console.promptYesNo("Do you want to continue?");

if (shouldContinue) {
console.log("Continuing...");
} else {
console.log("Operation cancelled");
exit(0);
}

Generated Bash:

while true; do
read -p "Do you want to continue? (y/n): " yn
case $yn in
[Yy]* ) shouldContinue=true; break;;
[Nn]* ) shouldContinue=false; break;;
* ) echo "Please answer yes or no.";;
esac
done

if [ "${shouldContinue}" = "true" ]; then
echo "Continuing..."
else
echo "Operation cancelled"
exit 0
fi

Test Coverage:

  • File: tests/positive_fixtures/console_prompt_yesno.shx
  • Tests yes/no prompt functionality with proper bash case handling

System Information

console.isSudo()

Check if the script is running with sudo privileges:

if (console.isSudo()) {
console.log("Running with administrator privileges");
} else {
console.log("Running as regular user");
console.log("Some operations may require sudo");
}

Generated Bash:

if [ "$EUID" -eq 0 ]; then
echo "Running with administrator privileges"
else
echo "Running as regular user"
echo "Some operations may require sudo"
fi

Test Coverage:

  • File: tests/positive_fixtures/console_issudo.shx
  • Tests privilege detection using $EUID variable

console.isInteractive()

Check if the script is running in an interactive terminal session:

if (console.isInteractive()) {
console.log("Running in interactive mode - can show prompts");
let name: string = console.promptText("Enter your name");
console.log(`Hello, ${name}!`);
} else {
console.log("Running in non-interactive mode");
console.log("Using default configuration");
}

Generated Bash:

if [ -t 0 ]; then
echo "Running in interactive mode - can show prompts"
name=$(while true; do read -p "Enter your name: " input; if [ -n "${input}" ]; then echo "${input}"; break; else echo "Please enter a valid name."; fi; done)
echo "Hello, ${name}!"
else
echo "Running in non-interactive mode"
echo "Using default configuration"
fi

Use Cases:

  • Adaptive Scripts: Show prompts only when running interactively
  • Automation Support: Provide non-interactive fallbacks for CI/CD pipelines
  • Background Processing: Detect when scripts run in background or as cron jobs
  • Error Prevention: Avoid script hangs when prompts can't be displayed

Test Coverage:

  • File: tests/positive_fixtures/console_isinteractive.shx
  • Tests TTY detection using [ -t 0 ] bash test

console.getShell()

Detect the current shell being used to execute the script:

let currentShell: string = console.getShell();
console.log(`Running in: ${currentShell}`);

if (currentShell == "bash") {
console.log("Using Bash-specific features");
} else if (currentShell == "zsh") {
console.log("Using Zsh-specific features");
} else if (currentShell == "fish") {
console.log("Using Fish-specific features");
} else {
console.log(`Shell ${currentShell} detected - using POSIX features`);
}

Generated Bash:

currentShell=$(basename "${SHELL:-$0}")
echo "Running in: ${currentShell}"

if [ "${currentShell}" = "bash" ]; then
echo "Using Bash-specific features"
elif [ "${currentShell}" = "zsh" ]; then
echo "Using Zsh-specific features"
elif [ "${currentShell}" = "fish" ]; then
echo "Using Fish-specific features"
else
echo "Shell ${currentShell} detected - using POSIX features"
fi

Use Cases:

  • Feature Detection: Enable shell-specific features when available
  • Compatibility: Provide fallbacks for different shell environments
  • Debugging: Log the execution environment for troubleshooting
  • Script Adaptation: Adjust behavior based on shell capabilities

Test Coverage:

  • File: tests/positive_fixtures/console_getshell.shx
  • Tests shell detection using $SHELL environment variable

Dialog Functions

Utah provides comprehensive dialog functions for creating interactive terminal user interfaces. These functions automatically detect and use the best available dialog system (dialog, whiptail, or fallback to basic prompts).

Message Display Functions

console.showMessage()

Show a general message dialog:

console.showMessage("Welcome", "Welcome to Utah Dialog Demo!");
console.showMessage("Update", "System update completed successfully");

Generated Bash:

if command -v dialog >/dev/null 2>&1; then
dialog --title "Welcome" --msgbox "Welcome to Utah Dialog Demo!" 8 50
elif command -v whiptail >/dev/null 2>&1; then
whiptail --title "Welcome" --msgbox "Welcome to Utah Dialog Demo!" 8 50
else
echo "Welcome: Welcome to Utah Dialog Demo!"
read -p "Press Enter to continue..."
fi

console.showInfo()

Show an informational message:

console.showInfo("Information", "Process completed successfully");

console.showWarning()

Show a warning message:

console.showWarning("Warning", "This action cannot be undone");

console.showError()

Show an error message:

console.showError("Error", "Failed to connect to server");

console.showSuccess()

Show a success message:

console.showSuccess("Success", "File uploaded successfully");

User Input Functions

console.promptText()

Prompt for text input with optional default value:

let name: string = console.promptText("Enter your name", "John Doe");
let email: string = console.promptText("Enter your email");

Generated Bash:

if command -v dialog >/dev/null 2>&1; then
name=$(dialog --title "Input" --inputbox "Enter your name" 8 50 "John Doe" 2>&1 >/dev/tty)
elif command -v whiptail >/dev/null 2>&1; then
name=$(whiptail --title "Input" --inputbox "Enter your name" 8 50 "John Doe" 2>&1 >/dev/tty)
else
read -p "Enter your name [John Doe]: " name
name=${name:-"John Doe"}
fi

console.promptPassword()

Prompt for password input (hidden):

let password: string = console.promptPassword("Enter your password");

Generated Bash:

if command -v dialog >/dev/null 2>&1; then
password=$(dialog --title "Password" --passwordbox "Enter your password" 8 50 2>&1 >/dev/tty)
elif command -v whiptail >/dev/null 2>&1; then
password=$(whiptail --title "Password" --passwordbox "Enter your password" 8 50 2>&1 >/dev/tty)
else
read -s -p "Enter your password: " password
echo
fi

console.promptNumber()

Prompt for numeric input with validation:

let age: number = console.promptNumber("Enter your age", 18, 120, 25);
let port: number = console.promptNumber("Enter port number", 1, 65535);

console.promptFile()

Prompt for file selection:

let configFile: string = console.promptFile("Select config file", "*.json");
let logFile: string = console.promptFile("Select log file");

console.promptDirectory()

Prompt for directory selection:

let workDir: string = console.promptDirectory("Choose working directory", "/tmp");
let backupDir: string = console.promptDirectory("Select backup directory");

Choice and Confirmation Functions

console.showChoice()

Show a single choice menu:

let color: string = console.showChoice(
"Color Selection",
"Choose your favorite color:",
"Red,Green,Blue,Yellow",
0 // default selection index
);

Generated Bash:

if command -v dialog >/dev/null 2>&1; then
color=$(dialog --title "Color Selection" --menu "Choose your favorite color:" 15 50 4 \
"Red" "" "Green" "" "Blue" "" "Yellow" "" 2>&1 >/dev/tty)
elif command -v whiptail >/dev/null 2>&1; then
color=$(whiptail --title "Color Selection" --menu "Choose your favorite color:" 15 50 4 \
"Red" "" "Green" "" "Blue" "" "Yellow" "" 2>&1 >/dev/tty)
else
echo "Choose your favorite color:"
echo "1) Red"
echo "2) Green"
echo "3) Blue"
echo "4) Yellow"
read -p "Enter choice [1]: " choice
choice=${choice:-1}
case $choice in
1) color="Red" ;;
2) color="Green" ;;
3) color="Blue" ;;
4) color="Yellow" ;;
*) color="Red" ;;
esac
fi

console.showMultiChoice()

Show a multi-choice checklist:

let features: string = console.showMultiChoice(
"Features",
"Select features to enable:",
"Logging,Monitoring,Analytics,Backup",
"Logging,Monitoring" // default selections
);

console.showConfirm()

Show a yes/no confirmation dialog:

let confirmed: boolean = console.showConfirm(
"Confirm Action",
"Are you sure you want to continue?",
"yes" // default button
);

Progress Display

console.showProgress()

Show a progress indicator:

console.showProgress("Processing", "Loading data...", 75, false);
console.showProgress("Upload", "Uploading files...", 50, true); // cancellable

Dialog System Compatibility

The dialog functions use a three-tier fallback system:

  1. Primary: dialog command (full-featured TUI with rich widgets)
  2. Secondary: whiptail command (lightweight TUI for basic environments)
  3. Fallback: Basic terminal prompts using read and echo

This ensures compatibility across different environments while providing the best possible user experience.

Test Coverage

  • Files: tests/positive_fixtures/console_show*.shx and tests/positive_fixtures/console_prompt*.shx
  • Tests all dialog functions with proper fallback handling
  • Covers both expression and statement-level usage

Practical Examples

Interactive Setup Script with Dialogs

script.description("Application setup wizard with rich dialogs");

// Welcome message
console.showMessage("Setup Wizard", "Welcome to the application setup!");

// Get user information with rich input dialogs
let userName: string = console.promptText("Your name", "User");
let userEmail: string = console.promptText("Your email address");
let userAge: number = console.promptNumber("Your age", 18, 120, 25);

// Choose installation type
let installType: string = console.showChoice(
"Installation Type",
"Choose installation type:",
"Quick,Custom,Advanced",
0
);

// Multi-select features
let features: string = console.showMultiChoice(
"Features",
"Select features to enable:",
"Logging,Monitoring,Analytics,Backup",
"Logging,Monitoring"
);

// Show configuration summary
let summary: string = `
Name: ${userName}
Email: ${userEmail}
Age: ${userAge}
Type: ${installType}
Features: ${features}
`;

console.showInfo("Configuration Summary", summary);

// Confirm installation
let confirmed: boolean = console.showConfirm(
"Confirm Setup",
"Proceed with installation?",
"yes"
);

if (confirmed) {
// Show progress
console.showProgress("Installing", "Setting up application...", 25, false);
`$(sleep 1)`;
console.showProgress("Installing", "Configuring features...", 50, false);
`$(sleep 1)`;
console.showProgress("Installing", "Finalizing setup...", 100, false);

console.showSuccess("Complete", "Installation completed successfully!");
} else {
console.showWarning("Cancelled", "Installation was cancelled");
}

User Confirmation Flow

script.description("File deletion utility with confirmation");

args.define("--file", "-f", "File to delete", "string", true);

let filename: string = args.get("--file");

if (!fs.exists(filename)) {
console.log("Error: File not found: ${filename}");
exit(1);
}

console.log("File: ${filename}");
console.log("Size: $(stat -c%s "${filename}") bytes");

let confirmed: boolean = console.promptYesNo("Are you sure you want to delete ${filename}?");

if (confirmed) {
console.log("Deleting ${filename}...");
"$(rm "${filename}")";
console.log("File deleted successfully");
} else {
console.log("Deletion cancelled");
}

Interactive Setup Script

script.description("Application setup wizard");

console.clear();
console.log("=== Application Setup Wizard ===");

let appName: string = console.prompt("Enter application name: ");
let port: string = console.prompt("Enter port number (default 3000): ");
if (port == "") {
port = "3000";
}

let enableSSL: boolean = console.promptYesNo("Enable SSL?");
let enableDebug: boolean = console.promptYesNo("Enable debug mode?");

console.log("\n=== Configuration Summary ===");
console.log("Application Name: ${appName}");
console.log("Port: ${port}");
console.log("SSL Enabled: ${enableSSL}");
console.log("Debug Mode: ${enableDebug}");

let saveConfig: boolean = console.promptYesNo("\nSave this configuration?");

if (saveConfig) {
let config: object = json.parse('{}');
config = json.set(config, ".name", appName);
config = json.set(config, ".port", port);
config = json.set(config, ".ssl", enableSSL ? "true" : "false");
config = json.set(config, ".debug", enableDebug ? "true" : "false");

let configJson: string = json.stringify(config, true);
fs.writeFile("config.json", configJson);

console.log("Configuration saved to config.json");
} else {
console.log("Configuration not saved");
}

Permission Checker

script.description("System permission and capability checker");

console.log("=== System Permission Check ===");

// Check if running as root/sudo
if (console.isSudo()) {
console.log("✓ Running with administrative privileges");

// Check system directories
if (fs.exists("/etc")) {
console.log("✓ Can access system configuration directory");
}

if (fs.exists("/var/log")) {
console.log("✓ Can access system log directory");
}

} else {
console.log("⚠ Running as regular user");

let needsRoot: boolean = console.promptYesNo("This script may need root privileges. Continue anyway?");
if (!needsRoot) {
console.log("Please run with sudo for full functionality:");
console.log("sudo utah run " + args.getScriptName());
exit(1);
}
}

// Check specific capabilities
console.log("\n=== Capability Check ===");

if (os.isInstalled("systemctl")) {
console.log("✓ systemctl available - can manage services");
} else {
console.log("✗ systemctl not available");
}

if (os.isInstalled("docker")) {
console.log("✓ Docker available");
} else {
console.log("✗ Docker not available");
}

if (fs.exists("/proc/version")) {
let kernelVersion: string = `$(cat /proc/version | awk '{print $3}')`;
console.log("✓ Kernel version: ${kernelVersion}");
}

Progress Indicator

script.description("Long-running process with progress updates");

let tasks: string[] = [
"Initializing system",
"Loading configuration",
"Connecting to database",
"Processing data",
"Generating reports",
"Cleaning up"
];

let total: number = tasks.length;

console.log("Starting process with ${total} tasks...\n");

for (let i: number = 0; i < total; i++) {
let current: number = i + 1;
let task: string = tasks[i];
let percent: number = (current * 100) / total;

console.log("[${current}/${total}] (${percent}%) ${task}...");

// Simulate work (in real script, this would be actual work)
`$(sleep 1)`;

console.log("✓ ${task} completed");
}

console.log("\n✓ All tasks completed successfully!");

Error Recovery Dialog

function handleError(operation: string, error: string): boolean {
console.log("\n❌ Error during ${operation}:");
console.log(" ${error}");

console.log("\nOptions:");
console.log("1. Retry the operation");
console.log("2. Skip and continue");
console.log("3. Abort the script");

let choice: string = console.prompt("Choose an option (1-3): ");

if (choice == "1") {
console.log("Retrying...");
return true; // retry
} else if (choice == "2") {
console.log("Skipping this operation...");
return false; // skip
} else {
console.log("Aborting script...");
exit(1);
}
}

// Usage example
let retryCount: number = 0;
let maxRetries: number = 3;

while (retryCount < maxRetries) {
try {
// Attempt some operation
let result: string = `$(wget -q --spider http://example.com && echo "success" || echo "failed")`;

if (result == "success") {
console.log("✓ Connection test successful");
break;
} else {
if (handleError("connection test", "Unable to reach example.com")) {
retryCount++;
continue; // retry
} else {
break; // skip
}
}
}
catch {
if (handleError("connection test", "Network error occurred")) {
retryCount++;
continue; // retry
} else {
break; // skip
}
}
}

if (retryCount >= maxRetries) {
console.log("Maximum retry attempts reached");
}

Best Practices

1. Provide Clear Prompts

// Good - clear and specific
let dbPassword: string = console.prompt("Enter database password (will not echo): ");
let confirmDelete: boolean = console.promptYesNo("Delete all log files? This cannot be undone.");

// Avoid - unclear prompts
let input: string = console.prompt("Enter value: ");
let confirm: boolean = console.promptYesNo("Continue? ");

2. Validate User Input

function getValidPort(): number {
while (true) {
let portStr: string = console.prompt("Enter port number (1-65535): ");
let port: number = portStr;

if (port >= 1 && port <= 65535) {
return port;
} else {
console.log("Invalid port number. Please enter a value between 1 and 65535.");
}
}
}

let serverPort: number = getValidPort();

3. Provide Feedback

// Good - immediate feedback
console.log("Connecting to server...");
let connected: boolean = connectToServer();
if (connected) {
console.log("✓ Connected successfully");
} else {
console.log("✗ Connection failed");
}

// Avoid - silent operations
let result: boolean = connectToServer();

4. Use Appropriate Privilege Checks

function requireRoot(): void {
if (!console.isSudo()) {
console.log("This operation requires root privileges.");
console.log("Please run with sudo:");
console.log("sudo utah run ${args.getScriptName()}");
exit(1);
}
}

// Only require root when actually needed
if (args.has("--system-install")) {
requireRoot();
}

5. Adapt to Execution Environment

function setupConfiguration(): void {
let configFile: string;

if (console.isInteractive()) {
// Interactive mode - can prompt user
configFile = console.promptFile("Select config file", "*.json");
} else {
// Non-interactive mode - use environment or defaults
configFile = env.get("CONFIG_FILE") || "/etc/app/default.json";
if (!fs.exists(configFile)) {
console.log("Error: Config file not found and not in interactive mode");
console.log("Set CONFIG_FILE environment variable or run interactively");
exit(1);
}
}

console.log(`Using config: ${configFile}`);
}

5. Format Output Consistently

// Use consistent symbols and formatting
console.log("=== System Health Check ===");
console.log("✓ Service A is running");
console.log("✓ Service B is running");
console.log("⚠ Service C has warnings");
console.log("✗ Service D is stopped");
console.log("================================");

Function Reference Summary

FunctionPurposeReturn TypeParametersExample
console.log(message)Print messagevoidmessage: stringconsole.log("Hello")
console.clear()Clear screenvoidnoneconsole.clear()
console.prompt(message)Get user inputstringmessage: stringlet name = console.prompt("Name: ")
console.promptYesNo(message)Get yes/no inputbooleanmessage: stringlet ok = console.promptYesNo("Continue? ")
console.isSudo()Check root privilegesbooleannoneif (console.isSudo()) { ... }
console.isInteractive()Check if interactivebooleannoneif (console.isInteractive()) { ... }
console.getShell()Get current shell namestringnonelet shell = console.getShell()

Dialog Functions Reference

FunctionPurposeReturn TypeParametersExample
console.showMessage(title, message)General message dialogvoidtitle: string, message: stringconsole.showMessage("Info", "Done")
console.showInfo(title, message)Information messagevoidtitle: string, message: stringconsole.showInfo("Info", "Success")
console.showWarning(title, message)Warning messagevoidtitle: string, message: stringconsole.showWarning("Warning", "Check logs")
console.showError(title, message)Error messagevoidtitle: string, message: stringconsole.showError("Error", "Failed")
console.showSuccess(title, message)Success messagevoidtitle: string, message: stringconsole.showSuccess("Success", "Complete")
console.showChoice(title, message, options, defaultIndex?)Single choice menustringtitle: string, message: string, options: string, defaultIndex?: numberlet color = console.showChoice("Pick", "Color:", "Red,Blue", 0)
console.showMultiChoice(title, message, options, defaultSelected?)Multi-choice checkliststringtitle: string, message: string, options: string, defaultSelected?: stringlet features = console.showMultiChoice("Features", "Select:", "A,B,C", "A,B")
console.showConfirm(title, message, defaultButton?)Yes/no confirmationbooleantitle: string, message: string, defaultButton?: stringlet ok = console.showConfirm("Confirm", "Continue?", "yes")
console.showProgress(title, message, percent, canCancel?)Progress displayvoidtitle: string, message: string, percent: number, canCancel?: booleanconsole.showProgress("Loading", "Please wait...", 75, false)
console.promptText(prompt, defaultValue?, validation?)Text input promptstringprompt: string, defaultValue?: string, validation?: stringlet name = console.promptText("Name:", "John")
console.promptPassword(prompt)Password input (hidden)stringprompt: stringlet pwd = console.promptPassword("Password:")
console.promptNumber(prompt, min?, max?, defaultValue?)Numeric input with validationnumberprompt: string, min?: number, max?: number, defaultValue?: numberlet age = console.promptNumber("Age:", 1, 150, 25)
console.promptFile(prompt, filter?)File selection dialogstringprompt: string, filter?: stringlet file = console.promptFile("Config:", "*.json")
console.promptDirectory(prompt, defaultPath?)Directory selection dialogstringprompt: string, defaultPath?: stringlet dir = console.promptDirectory("Folder:", "/tmp")

The console functions provide essential user interaction capabilities for Utah scripts, making them more interactive and user-friendly while maintaining the robustness expected from system automation tools.