From b750a9b71ed8647bc597db694d815abe7dd1f154 Mon Sep 17 00:00:00 2001 From: Cormac Shannon Date: Fri, 29 Aug 2025 00:18:21 +0100 Subject: [PATCH] wow --- README.md | 328 ++++++++++++++++++++++++++++++++++++ SPEC.md | 38 +++++ __injected_lib.lua | 33 ++++ demo_quick_examples.luash | 75 +++++++++ demos/basic.luash | 40 +++++ demos/data_processing.luash | 158 +++++++++++++++++ demos/development.luash | 126 ++++++++++++++ demos/quick_examples.luash | 75 +++++++++ demos/run_demo.luash_ | 47 ++++++ demos/showcase.luash | 124 ++++++++++++++ demos/system_admin.luash | 78 +++++++++ demos/test.luash | 20 +++ interpolation_demo.luash | 31 ++++ luash | 184 ++++++++++++++++++++ showcase.luash | 124 ++++++++++++++ system_report.txt | 4 + 16 files changed, 1485 insertions(+) create mode 100644 README.md create mode 100644 SPEC.md create mode 100644 __injected_lib.lua create mode 100644 demo_quick_examples.luash create mode 100644 demos/basic.luash create mode 100644 demos/data_processing.luash create mode 100644 demos/development.luash create mode 100644 demos/quick_examples.luash create mode 100644 demos/run_demo.luash_ create mode 100644 demos/showcase.luash create mode 100644 demos/system_admin.luash create mode 100644 demos/test.luash create mode 100644 interpolation_demo.luash create mode 100755 luash create mode 100644 showcase.luash create mode 100644 system_report.txt diff --git a/README.md b/README.md new file mode 100644 index 0000000..6c3bedd --- /dev/null +++ b/README.md @@ -0,0 +1,328 @@ +# Luash - Minimal Lua Shell Scripting + +A lightweight Lua preprocessor that makes Lua a capable shell scripting language, combining the readability of Lua with the power of shell commands. + +## Why Luash? + +**Clean Syntax**: No more `$((arithmetic))`, `${parameter:-default}`, or complex quoting nightmares +**Real Programming**: Full Lua language features - tables, functions, proper data structures +**Shell Integration**: Seamless shell command execution with familiar syntax +**Minimal**: Just 4 core functions, no bloat + +## Quick Start + +```bash +#!/usr/bin/env luash + +# Environment variables (clean syntax) +print("Hello " .. $USER .. "!") + +# Variable assignment +$MY_VAR = "some value" + +# Shell commands with backticks +files = `ls -la` +current_dir = `pwd` + +# Interactive commands +!git status + +# The power of Lua + shell +if `test -f README.md` ~= "" then + lines = `wc -l < README.md` + print("README has " .. lines .. " lines") +end +``` + +## Core Features + +### Environment Variables +```lua +# Access with clean $ syntax +print("User: " .. $USER) +print("Shell: " .. $SHELL) + +# Assignment +$MY_VAR = "hello world" +print($MY_VAR) + +# Inside strings are preserved literally +print("This prints: $USER (not substituted)") +``` + +### Shell Commands +```lua +# Command substitution with backticks +files = `ls -la` +date = `date +%Y-%m-%d` + +# Variable interpolation in commands +service = "ssh" +result = `pgrep #{service} | wc -l` + +host = "google.com" +ping_result = `ping -c 1 #{host} >/dev/null 2>&1 && echo "ok"` + +# Interactive commands (direct output) +!git status +!top +``` + +### The Power of Lua +```lua +# Real data structures +users = {"alice", "bob", "charlie"} +for i = 1, #users do + print("User " .. i .. ": " .. users[i]) +end + +# Functions and logic +function backup_file(filename) + if `test -f ` .. filename .. `` ~= "" then + `cp ` .. filename .. ` ` .. filename .. `.bak` + return true + end + return false +end +``` + +## Live Demos + +Run these demos to see luash in action: + +```bash +# Basic features demo +./luash demo_basic.luash + +# Quick comparison with bash +./luash demo_quick_examples.luash + +# System administration tasks +./luash demo_system_admin.luash + +# Development workflow automation +./luash demo_development.luash + +# Data processing and analysis +./luash demo_data_processing.luash + +# Interactive demo runner +./luash run_demos.luash +``` + +### What You Get + +#### File System Operations +```lua +-- Check file existence +if fs.exists("config.txt") then + content = fs.read("config.txt") +end + +-- File operations +fs.write("output.txt", "Hello World") +fs.append("log.txt", "New entry\n") + +-- Advanced file operations +file.copy("source.txt", "backup.txt") +file.move("old.txt", "new.txt") +lines = file.lines("data.txt") -- Read as array of lines +``` + +#### Directory Operations +```lua +-- Directory management +dir.create("new_folder") -- mkdir -p equivalent +files = dir.list("/tmp") -- List directory contents +current = dir.pwd() -- Get current directory + +-- Convenience aliases +mkdir("test") +cd("/home/user") +ls("/var/log") +``` + +#### String Utilities +```lua +-- String manipulation +parts = str.split("a,b,c", ",") +clean = str.trim(" whitespace ") +bool = str.starts_with("hello", "hel") + +-- Text processing +result = text.grep("pattern", "file.txt") +lines = text.head(10, "large_file.txt") +count = text.wc("-l", "data.txt") -- Line count +``` + +#### Array/Table Operations +```lua +-- Array utilities +found = array.contains({"a", "b", "c"}, "b") +doubled = array.map({1, 2, 3}, function(x) return x * 2 end) +evens = array.filter({1, 2, 3, 4}, function(x) return x % 2 == 0 end) +``` + +#### Path Utilities +```lua +-- Path manipulation +full_path = path.join("/usr", "local", "bin", "luash") +dir_name = path.dirname("/path/to/file.txt") -- "/path/to" +base_name = path.basename("/path/to/file.txt") -- "file.txt" +extension = path.ext("document.pdf") -- "pdf" +``` + +#### System Information +```lua +-- System utilities +os_name = sys.os() -- "linux", "darwin", etc. +arch = sys.arch() -- "x86_64", "arm64", etc. +hostname = sys.hostname() -- Get machine name +user = sys.whoami() -- Current username +memory_info = sys.memory() -- Memory usage +disk_info = sys.disk("/") -- Disk usage +``` + +#### Network Operations +```lua +-- Network utilities +success = net.download("https://example.com/file.txt", "local_file.txt") +response = net.get("https://api.example.com/data") +post_result = net.post("https://api.example.com/submit", "key=value") +reachable = net.ping("google.com", 3) -- Ping 3 times +``` + +#### Process Management +```lua +-- Process operations +my_pid = proc.pid() +git_path = proc.which("git") -- Find executable path + +-- Job control +job.background("long_running_command") +job.kill(1234, "TERM") -- Kill process by PID +job.killall("firefox") -- Kill all processes by name +processes = job.ps() -- Get process list +``` + +#### Logging and Colors +```lua +-- Colored logging +log.info("Information message") +log.warn("Warning message") +log.error("Error message") +log.success("Success message") + +-- Color output +print(color.red("Error text")) +print(color.green("Success text")) +print(color.bold(color.yellow("Important notice"))) +``` + +#### Archive Operations +```lua +-- Compression utilities +archive.tar_create("backup.tar.gz", {"file1.txt", "file2.txt"}) +archive.tar_extract("backup.tar.gz", "/destination") +archive.zip_create("archive.zip", {"folder1", "folder2"}) +archive.zip_extract("archive.zip", "/extract_here") +``` + +### Convenience Aliases + +Common shell commands are available as Lua functions: + +```lua +ls() -- ls -la +pwd() -- Get current directory +cd("/path") -- Change directory +mkdir("folder") -- Create directory +rm("file") -- Remove file +cp("src", "dst") -- Copy file +mv("old", "new") -- Move/rename file +cat("file.txt") -- Read file contents +echo("Hello") -- Print and return text +grep("pattern", "file.txt") -- Search in file +head(5, "file.txt") -- First 5 lines +tail(10, "file.txt") -- Last 10 lines +wc("-l", "file.txt") -- Count lines +``` + +## Usage + +### Basic Usage +```bash +./luash script.luash +``` + +### Debug Mode +```bash +LUASH_DEBUG=1 ./luash script.luash +``` + +### Example Script +See `example.luash` for a comprehensive demonstration of all features. + +## Installation + +1. Clone or download the luash repository +2. Make the script executable: `chmod +x luash` +3. Optionally, add to your PATH for system-wide access + +## Syntax Examples + +### Environment Variables in Strings +```lua +-- These will substitute environment variables +message = "Hello ${USER}, your shell is ${SHELL}" +path = "$HOME/Documents" + +-- These will print literally (inside double quotes) +print("This will just print normally $SHELL") +print("This will substitute with the environment variable ${SHELL}") +``` + +### Command Interpolation +```lua +-- Variable substitution in commands +branch = "main" +result = `git checkout #{branch}` + +-- Multiple variables +user = "john" +host = "server.com" +output = `ssh #{user}@#{host} 'ls -la'` +``` + +### File Processing Pipeline +```lua +-- Read, process, and write files +lines = file.lines("input.txt") +processed = array.map(lines, function(line) + return str.trim(line):upper() +end) +file.write_lines("output.txt", processed) +``` + +## Why Luash? + +- **Readable**: Lua's clean syntax is more maintainable than bash +- **Powerful**: Full programming language features (tables, functions, modules) +- **Fast**: Lua is lightweight and executes quickly +- **Portable**: Works on any system with Lua installed +- **Safe**: Better error handling than shell scripts +- **Familiar**: Shell-like utilities with programming language benefits + +## Preprocessor Pipeline + +Luash applies several preprocessing steps: + +1. **Environment Variable Substitution**: `$VAR` and `${VAR}` → `env.get('VAR')` +2. **Interactive Command Processing**: `!command` → `run('command')` +3. **Shell Command Substitution**: `` `command` `` → `shell('command')` +4. **Variable Interpolation**: `#{var}` in commands → Lua string concatenation +5. **Library Injection**: Comprehensive shell utilities loaded automatically + +## License + +This project is designed to make shell scripting more pleasant and maintainable while retaining the power and familiarity of traditional shell tools. diff --git a/SPEC.md b/SPEC.md new file mode 100644 index 0000000..5b33c95 --- /dev/null +++ b/SPEC.md @@ -0,0 +1,38 @@ +# Luash + +A lua preprocessor for shell scripting. + +## Why + +Although traditional POSIX shells are highly portable and can be extremely fast, their syntax can be arduous to read. + +Lua is a lightweight and fast language that already has the features needed to become a great scripting language. + +This project aims to add syntactic sugar to make the process of write commands in lua much easier. + +Inspired by other projects such as Xonsh and Ruby. + +## Features + +Shell execution via backticks + +```lua +files = `ls -a` +``` + +Variable substitution in shell commands + +```lua +dir = "/" +files = `ls #{dir}` +``` + +Environment variable access + +```lua +print($SHELL) +terminal = $TERM + +print("This will just print normally $SHELL") +print("This will substitute with the environment variable ${SHELL}") +``` \ No newline at end of file diff --git a/__injected_lib.lua b/__injected_lib.lua new file mode 100644 index 0000000..7414823 --- /dev/null +++ b/__injected_lib.lua @@ -0,0 +1,33 @@ +-- Minimal luash helper functions + +-- Local environment variable storage +local env_vars = {} + +-- Environment variable access +function env_get(name) + -- Check local storage first, then system environment + return env_vars[name] or os.getenv(name) or "" +end + +function env_set(name, value) + -- Store locally for this session + env_vars[name] = tostring(value) + -- Also try to set for subprocesses with proper quoting + local quoted_value = "'" .. tostring(value):gsub("'", "'\"'\"'") .. "'" + os.execute("export " .. name .. "=" .. quoted_value) +end + +-- Shell command execution +function shell(command) + local handle = io.popen(command, "r") + if not handle then return "" end + local output = handle:read("*a") + handle:close() + -- Remove trailing newlines + return (output or ""):gsub("[\r\n]+$", "") +end + +-- Interactive command execution (shows output directly) +function run(command) + return os.execute(command) +end diff --git a/demo_quick_examples.luash b/demo_quick_examples.luash new file mode 100644 index 0000000..bfa8acb --- /dev/null +++ b/demo_quick_examples.luash @@ -0,0 +1,75 @@ +#!/usr/bin/env luash +-- Quick Examples: Bite-sized demos showing luash vs bash + +print("=== Luash vs Bash: Quick Examples ===\n") + +print("1. Environment Variables") +print(" Bash: echo $USER") +print(" Luash: print($USER)") +print(" → " .. $USER) + +print("\n2. Variable Assignment") +print(" Bash: MY_VAR=\"hello\"") +print(" Luash: $MY_VAR = \"hello\"") +$MY_VAR = "hello" +print(" → " .. $MY_VAR) + +print("\n3. Command Substitution") +print(" Bash: current_dir=$(pwd)") +print(" Luash: current_dir = `pwd`") +current_dir = `pwd` +print(" → " .. current_dir) + +print("\n4. Conditional Logic") +print(" Bash: if [ -f \"README.md\" ]; then echo \"exists\"; fi") +print(" Luash: if `test -f README.md` == \"\" then print(\"missing\") else print(\"exists\") end") +if `test -f README.md && echo "yes"` == "yes" then + print(" → exists") +else + print(" → missing") +end + +print("\n5. Loops with Arrays") +print(" Bash: for file in *.lua; do echo $file; done") +print(" Luash: files = `ls *.lua`; for file in files:gmatch(\"[^\\n]+\") do print(file) end") +files = `ls *.luash` +print(" → Files found:") +for file in files:gmatch("[^\n]+") do + print(" " .. file) +end + +print("\n6. String Processing") +print(" Bash: echo \"hello world\" | tr '[:lower:]' '[:upper:]'") +print(" Luash: string.upper(\"hello world\")") +print(" → " .. string.upper("hello world")) + +print("\n7. Math Operations") +print(" Bash: result=$((5 + 3))") +print(" Luash: result = 5 + 3") +result = 5 + 3 +print(" → " .. result) + +print("\n8. File Operations") +print(" Bash: cat file.txt | wc -l") +print(" Luash: line_count = `cat luash | wc -l`") +line_count = `cat luash | wc -l` +print(" → " .. line_count .. " lines in luash script") + +print("\n9. Error Handling") +print(" Bash: command || echo \"failed\"") +print(" Luash: if `command 2>/dev/null` == \"\" then print(\"failed\") end") +if `nonexistent_command 2>/dev/null` == "" then + print(" → command failed (as expected)") +end + +print("\n10. Complex Data Structures") +print(" Bash: (limited array support)") +print(" Luash: Full Lua tables!") +data = { + users = {"alice", "bob", "charlie"}, + scores = {alice = 95, bob = 87, charlie = 92} +} +print(" → Users: " .. table.concat(data.users, ", ")) +print(" → Alice's score: " .. data.scores.alice) + +print("\n✨ Luash combines the best of shell scripting with Lua's power!") diff --git a/demos/basic.luash b/demos/basic.luash new file mode 100644 index 0000000..7dfd12e --- /dev/null +++ b/demos/basic.luash @@ -0,0 +1,40 @@ +#!/usr/bin/env luash +-- Basic Luash Demo: Environment Variables and Shell Commands + +print("=== Basic Luash Features ===\n") + +-- Environment variable access (clean syntax) +print("1. Environment Variables:") +print(" User: " .. $USER) +print(" Shell: " .. $SHELL) +print(" Home: " .. $HOME) + +-- Environment variable assignment +print("\n2. Setting Environment Variables:") +$MY_VAR = "Hello from Luash!" +print(" Set MY_VAR = " .. $MY_VAR) + +-- String literals preserve $ symbols +print("\n3. Strings preserve $ literals:") +print(" This prints literally: $USER and $HOME are variables") + +-- Shell command execution with backticks +print("\n4. Shell Commands:") +hostname = `hostname` +print(" Hostname: " .. hostname) + +date_info = `date +"%Y-%m-%d %H:%M:%S"` +print(" Current time: " .. date_info) + +-- Interactive commands for direct output +print("\n5. Interactive Commands:") +print(" Directory listing:") +!ls -la + +print("\n6. Combining Lua logic with shell:") +files = `ls -1` +file_count = 0 +for line in files:gmatch("[^\n]+") do + file_count = file_count + 1 +end +print(" Found " .. file_count .. " files in current directory") diff --git a/demos/data_processing.luash b/demos/data_processing.luash new file mode 100644 index 0000000..8c8072f --- /dev/null +++ b/demos/data_processing.luash @@ -0,0 +1,158 @@ +#!/usr/bin/env luash +-- Data Processing Demo: File processing, text manipulation, and analysis + +print("=== Data Processing with Luash ===\n") + +-- Create sample data for demonstration +print("1. Creating Sample Data:") +sample_data = [[timestamp,user,action,value +2024-01-01 10:00:00,alice,login,1 +2024-01-01 10:05:00,bob,purchase,25.50 +2024-01-01 10:10:00,alice,logout,1 +2024-01-01 10:15:00,charlie,login,1 +2024-01-01 10:20:00,bob,purchase,15.75 +2024-01-01 10:25:00,charlie,purchase,45.00]] + +-- Write sample data to file +local file = io.open("sample_data.csv", "w") +file:write(sample_data) +file:close() +print(" Sample CSV data created: sample_data.csv") + +-- File analysis using shell commands +print("\n2. File Analysis:") +line_count = `wc -l < sample_data.csv` +print(" Total lines: " .. line_count) + +file_size = `du -h sample_data.csv | cut -f1` +print(" File size: " .. file_size) + +-- Data extraction and filtering +print("\n3. Data Extraction:") +print(" Purchase transactions:") +!grep "purchase" sample_data.csv + +-- Using Lua for more complex processing +print("\n4. Advanced Processing with Lua:") +local data_file = io.open("sample_data.csv", "r") +local purchases = {} +local users = {} + +-- Skip header line +data_file:read("*line") + +-- Process each line +for line in data_file:lines() do + local timestamp, user, action, value = line:match("([^,]+),([^,]+),([^,]+),([^,]+)") + + if action == "purchase" then + table.insert(purchases, { + timestamp = timestamp, + user = user, + amount = tonumber(value) + }) + end + + users[user] = true +end +data_file:close() + +-- Calculate statistics +local total_amount = 0 +local purchase_count = #purchases +for i = 1, purchase_count do + total_amount = total_amount + purchases[i].amount +end + +local user_count = 0 +for user, _ in pairs(users) do + user_count = user_count + 1 +end + +print(" Statistics:") +print(" - Total users: " .. user_count) +print(" - Total purchases: " .. purchase_count) +print(" - Total revenue: $" .. string.format("%.2f", total_amount)) +print(" - Average purchase: $" .. string.format("%.2f", total_amount / purchase_count)) + +-- Log file processing +print("\n5. Log Processing:") +log_content = `tail -20 /var/log/system.log 2>/dev/null || echo "Log not accessible"` +if log_content ~= "Log not accessible" then + print(" Recent system log entries found") +else + -- Create a sample log for demonstration + sample_log = [[2024-01-01 10:00:01 INFO: Application started +2024-01-01 10:00:05 DEBUG: Database connection established +2024-01-01 10:00:10 WARN: High memory usage detected +2024-01-01 10:00:15 ERROR: Failed to connect to external API +2024-01-01 10:00:20 INFO: Retrying API connection +2024-01-01 10:00:25 INFO: API connection restored]] + + local log_file = io.open("sample.log", "w") + log_file:write(sample_log) + log_file:close() + + print(" Created sample.log for demonstration") + print(" Log analysis:") + + -- Count log levels + error_count = `grep -c "ERROR" sample.log` + warn_count = `grep -c "WARN" sample.log` + info_count = `grep -c "INFO" sample.log` + + print(" - Errors: " .. error_count) + print(" - Warnings: " .. warn_count) + print(" - Info messages: " .. info_count) +end + +-- Text transformation +print("\n6. Text Transformation:") +input_text = "Hello World, this is a TEST message" + +-- Using shell commands for text processing +upper_text = `echo "` .. input_text .. `" | tr '[:lower:]' '[:upper:]'` +print(" Uppercase: " .. upper_text) + +word_count = `echo "` .. input_text .. `" | wc -w` +print(" Word count: " .. word_count) + +-- Using Lua for more complex transformations +words = {} +for word in input_text:gmatch("%w+") do + table.insert(words, word) +end + +print(" Words: " .. table.concat(words, ", ")) +print(" Reversed: " .. table.concat(words, " "):reverse()) + +-- Batch file processing +print("\n7. Batch Processing:") +-- Create multiple sample files +for i = 1, 3 do + local batch_file = io.open("batch_" .. i .. ".txt", "w") + batch_file:write("Sample content for file " .. i .. "\n") + batch_file:write("Line 2 of file " .. i .. "\n") + batch_file:close() +end + +print(" Created 3 batch files") + +-- Process all batch files +batch_files = `ls batch_*.txt` +total_lines = 0 + +for filename in batch_files:gmatch("[^\n]+") do + local lines = `wc -l < ` .. filename + total_lines = total_lines + tonumber(lines) + print(" " .. filename .. ": " .. lines .. " lines") +end + +print(" Total lines across all files: " .. total_lines) + +-- Cleanup +print("\n8. Cleanup:") +!rm -f sample_data.csv sample.log batch_*.txt +print(" Temporary files cleaned up") + +print("\n✓ Data processing demo completed!") diff --git a/demos/development.luash b/demos/development.luash new file mode 100644 index 0000000..ab60000 --- /dev/null +++ b/demos/development.luash @@ -0,0 +1,126 @@ +#!/usr/bin/env luash +-- Development Workflow Demo: Git, building, and deployment tasks + +print("=== Development Workflow with Luash ===\n") + +-- Check if we're in a git repository +print("1. Git Repository Check:") +git_status = `git status 2>/dev/null || echo "not_a_repo"` +if git_status ~= "not_a_repo" then + current_branch = `git branch --show-current` + print(" ✓ Git repository detected") + print(" Current branch: " .. current_branch) + + -- Check for uncommitted changes + changes = `git status --porcelain` + if changes ~= "" then + print(" ⚠ Uncommitted changes detected") + else + print(" ✓ Working directory clean") + end +else + print(" ✗ Not a git repository") +end + +-- Project setup and dependency management +print("\n2. Project Dependencies:") +project_files = {"package.json", "requirements.txt", "Cargo.toml", "go.mod"} +for i = 1, #project_files do + local file = project_files[i] + local exists = `test -f ` .. file .. ` && echo "yes" || echo "no"` + if exists == "yes" then + print(" Found " .. file) + + -- Run appropriate install command + if file == "package.json" then + print(" Installing npm dependencies...") + !npm install + elseif file == "requirements.txt" then + print(" Python project detected") + !pip install -r requirements.txt + elseif file == "Cargo.toml" then + print(" Rust project detected") + !cargo build + elseif file == "go.mod" then + print(" Go project detected") + !go mod tidy + end + break + end +end + +-- Build and test automation +print("\n3. Build and Test:") +$BUILD_START = `date` +print(" Build started at: " .. $BUILD_START) + +-- Simple build logic based on project type +if `test -f Makefile && echo "yes"` == "yes" then + print(" Running make...") + build_result = `make 2>&1` + if string.find(build_result, "error") or string.find(build_result, "Error") then + print(" ✗ Build failed") + print(" " .. build_result) + else + print(" ✓ Build successful") + end +elseif `test -f package.json && echo "yes"` == "yes" then + print(" Running npm build...") + !npm run build 2>/dev/null || echo " No build script found" +else + print(" No build system detected") +end + +-- Code quality checks +print("\n4. Code Quality:") +code_files = `find . -name "*.lua" -o -name "*.js" -o -name "*.py" | head -10` +if code_files ~= "" then + line_count = `find . -name "*.lua" -o -name "*.js" -o -name "*.py" | xargs wc -l 2>/dev/null | tail -1 | awk '{print $1}'` + print(" Total lines of code: " .. line_count) + + file_count = `find . -name "*.lua" -o -name "*.js" -o -name "*.py" | wc -l` + print(" Code files: " .. file_count) +end + +-- Deployment preparation +print("\n5. Deployment Preparation:") +$VERSION = `git describe --tags 2>/dev/null || echo "v1.0.0"` +print(" Version: " .. $VERSION) + +-- Create deployment package +print(" Creating deployment package...") +package_name = "deploy_" .. string.gsub($VERSION, "%.", "_") .. ".tar.gz" + +-- Use Lua string manipulation instead of shell interpolation +!tar --exclude='.git' --exclude='node_modules' --exclude='*.log' -czf deploy_package.tar.gz . + +if `test -f deploy_package.tar.gz && echo "yes"` == "yes" then + package_size = `du -h deploy_package.tar.gz | cut -f1` + print(" ✓ Package created: deploy_package.tar.gz (" .. package_size .. ")") +else + print(" ✗ Package creation failed") +end + +-- Environment-specific deployment +print("\n6. Environment Deployment:") +$DEPLOY_ENV = "staging" -- Could be passed as argument +print(" Target environment: " .. $DEPLOY_ENV) + +-- Simulate deployment steps +deployment_steps = { + "Validating package integrity", + "Backing up current version", + "Uploading new version", + "Running database migrations", + "Restarting services", + "Running health checks" +} + +for i = 1, #deployment_steps do + print(" " .. i .. ". " .. deployment_steps[i] .. "...") + -- In real deployment, these would be actual commands + `sleep 0.5` -- Simulate work + print(" ✓ Complete") +end + +print("\n 🚀 Deployment to " .. $DEPLOY_ENV .. " completed successfully!") diff --git a/demos/quick_examples.luash b/demos/quick_examples.luash new file mode 100644 index 0000000..bfa8acb --- /dev/null +++ b/demos/quick_examples.luash @@ -0,0 +1,75 @@ +#!/usr/bin/env luash +-- Quick Examples: Bite-sized demos showing luash vs bash + +print("=== Luash vs Bash: Quick Examples ===\n") + +print("1. Environment Variables") +print(" Bash: echo $USER") +print(" Luash: print($USER)") +print(" → " .. $USER) + +print("\n2. Variable Assignment") +print(" Bash: MY_VAR=\"hello\"") +print(" Luash: $MY_VAR = \"hello\"") +$MY_VAR = "hello" +print(" → " .. $MY_VAR) + +print("\n3. Command Substitution") +print(" Bash: current_dir=$(pwd)") +print(" Luash: current_dir = `pwd`") +current_dir = `pwd` +print(" → " .. current_dir) + +print("\n4. Conditional Logic") +print(" Bash: if [ -f \"README.md\" ]; then echo \"exists\"; fi") +print(" Luash: if `test -f README.md` == \"\" then print(\"missing\") else print(\"exists\") end") +if `test -f README.md && echo "yes"` == "yes" then + print(" → exists") +else + print(" → missing") +end + +print("\n5. Loops with Arrays") +print(" Bash: for file in *.lua; do echo $file; done") +print(" Luash: files = `ls *.lua`; for file in files:gmatch(\"[^\\n]+\") do print(file) end") +files = `ls *.luash` +print(" → Files found:") +for file in files:gmatch("[^\n]+") do + print(" " .. file) +end + +print("\n6. String Processing") +print(" Bash: echo \"hello world\" | tr '[:lower:]' '[:upper:]'") +print(" Luash: string.upper(\"hello world\")") +print(" → " .. string.upper("hello world")) + +print("\n7. Math Operations") +print(" Bash: result=$((5 + 3))") +print(" Luash: result = 5 + 3") +result = 5 + 3 +print(" → " .. result) + +print("\n8. File Operations") +print(" Bash: cat file.txt | wc -l") +print(" Luash: line_count = `cat luash | wc -l`") +line_count = `cat luash | wc -l` +print(" → " .. line_count .. " lines in luash script") + +print("\n9. Error Handling") +print(" Bash: command || echo \"failed\"") +print(" Luash: if `command 2>/dev/null` == \"\" then print(\"failed\") end") +if `nonexistent_command 2>/dev/null` == "" then + print(" → command failed (as expected)") +end + +print("\n10. Complex Data Structures") +print(" Bash: (limited array support)") +print(" Luash: Full Lua tables!") +data = { + users = {"alice", "bob", "charlie"}, + scores = {alice = 95, bob = 87, charlie = 92} +} +print(" → Users: " .. table.concat(data.users, ", ")) +print(" → Alice's score: " .. data.scores.alice) + +print("\n✨ Luash combines the best of shell scripting with Lua's power!") diff --git a/demos/run_demo.luash_ b/demos/run_demo.luash_ new file mode 100644 index 0000000..e9c6d7f --- /dev/null +++ b/demos/run_demo.luash_ @@ -0,0 +1,47 @@ +#!/usr/bin/env luash +-- Demo Runner: Showcase all luash capabilities + +print("🚀 Welcome to Luash Demos!") +print("=" .. string.rep("=", 50)) + +demos = { + {name = "Basic Features", file = "demo_basic.luash", description = "Environment variables, shell commands, and string handling"}, + {name = "Quick Examples", file = "demo_quick_examples.luash", description = "Side-by-side comparison with bash"}, + {name = "System Administration", file = "demo_system_admin.luash", description = "Real-world sysadmin tasks"}, + {name = "Development Workflow", file = "demo_development.luash", description = "Git, building, and deployment automation"}, + {name = "Data Processing", file = "demo_data_processing.luash", description = "File processing and text analysis"} +} + +print("\nAvailable demos:") +for i = 1, #demos do + print(" " .. i .. ". " .. demos[i].name) + print(" " .. demos[i].description) +end + +print("\nEnter demo number (1-" .. #demos .. "), 'all' to run all demos, or 'q' to quit:") + +-- In a real interactive version, we'd read input +-- For now, let's run a specific demo or all +demo_choice = "1" -- Change this to test different demos + +if demo_choice == "all" then + for i = 1, #demos do + print("\n" .. string.rep("=", 60)) + print("Running Demo " .. i .. ": " .. demos[i].name) + print(string.rep("=", 60)) + !./luash $demos[i].file + print("\nPress Enter to continue...") + !read + end +elseif tonumber(demo_choice) and tonumber(demo_choice) >= 1 and tonumber(demo_choice) <= #demos then + local choice = tonumber(demo_choice) + print("\n" .. string.rep("=", 60)) + print("Running Demo: " .. demos[choice].name) + print(string.rep("=", 60)) + !./luash demos[choice].file +else + print("Running basic demo...") + !./luash demo_basic.luash +end + +print("\n✨ Thanks for trying Luash!") diff --git a/demos/showcase.luash b/demos/showcase.luash new file mode 100644 index 0000000..9957c5a --- /dev/null +++ b/demos/showcase.luash @@ -0,0 +1,124 @@ +#!/usr/bin/env luash +-- Luash Showcase: Highlight the best features + +print("🚀 Luash - Minimal Lua Shell Scripting") +print("=" .. string.rep("=", 45)) + +print("\n💡 Why Luash?") +print("✓ Clean syntax - no more bash quoting nightmares") +print("✓ Real programming language features") +print("✓ Seamless shell integration") +print("✓ Minimal and focused") + +print("\n📊 Quick Comparison:") +print("┌─────────────────┬─────────────────────┬─────────────────────┐") +print("│ Task │ Bash │ Luash │") +print("├─────────────────┼─────────────────────┼─────────────────────┤") +print("│ Variables │ VAR=\"value\" │ $VAR = \"value\" │") +print("│ Command Sub │ result=$(cmd) │ result = `cmd` │") +print("│ Conditionals │ if [ -f file ]; fi │ if `test -f file` │") +print("│ Arrays │ arr=(a b c) │ arr = {\"a\",\"b\",\"c\"} │") +print("│ Functions │ Limited │ Full Lua functions │") +print("└─────────────────┴─────────────────────┴─────────────────────┘") + +print("\n🎯 Live Examples:") + +print("\n1. Environment & Variables") +print(" Current user: " .. $USER) +$GREETING = "Hello from Luash" +print(" Custom var: " .. $GREETING) + +print("\n2. Shell Integration") +system_info = `uname -a` +print(" System: " .. system_info) + +file_count = `ls | wc -l` +print(" Files here: " .. file_count) + +print("\n3. Real Programming") +-- Lua's power: functions, tables, proper data types +function analyze_directory(path) + local files = `ls -la ` .. (path or ".") + local lines = {} + local file_count = 0 + local total_size = 0 + + for line in files:gmatch("[^\n]+") do + if not line:match("^total") and not line:match("^d") then + file_count = file_count + 1 + -- Extract size (5th field in ls -la) + local size = line:match("%S+%s+%S+%s+%S+%s+%S+%s+(%d+)") + if size then + total_size = total_size + tonumber(size) + end + end + end + + return file_count, total_size +end + +files, size = analyze_directory() +print(" Analysis: " .. files .. " files, " .. size .. " bytes total") + +print("\n4. Error Handling") +if `which git 2>/dev/null` ~= "" then + print(" ✓ Git is available") + if `git status 2>/dev/null` ~= "" then + branch = `git branch --show-current 2>/dev/null` + print(" Current branch: " .. branch) + else + print(" Not in a git repository") + end +else + print(" ✗ Git not installed") +end + +print("\n5. Data Processing") +-- Create and process some data +sample_data = { + {name = "Alice", score = 95}, + {name = "Bob", score = 87}, + {name = "Charlie", score = 92} +} + +total_score = 0 +for i = 1, #sample_data do + total_score = total_score + sample_data[i].score +end +average = total_score / #sample_data + +print(" Student scores processed:") +print(" Average: " .. string.format("%.1f", average)) + +-- Find highest scorer +best_student = sample_data[1] +for i = 2, #sample_data do + if sample_data[i].score > best_student.score then + best_student = sample_data[i] + end +end +print(" Top student: " .. best_student.name .. " (" .. best_student.score .. ")") + +print("\n🎪 Interactive Demo:") +print(" Let's see what's running on your system...") +!ps aux | head -5 + +print("\n📈 Performance:") +start_time = `date +%s.%N` +-- Simulate some work +for i = 1, 1000 do + local _ = string.upper("performance test " .. i) +end +end_time = `date +%s.%N` + +-- Calculate duration (requires bash-style arithmetic) +duration = tonumber(end_time) - tonumber(start_time) +print(" Processed 1000 operations in " .. string.format("%.3f", duration) .. " seconds") + +print("\n✨ Try these demos:") +print(" ./luash demo_quick_examples.luash # Side-by-side with bash") +print(" ./luash demo_system_admin.luash # Sysadmin tasks") +print(" ./luash demo_development.luash # Dev workflows") +print(" ./luash demo_data_processing.luash # Data analysis") + +print("\n🎉 Luash: Shell scripting that doesn't make you cry!") diff --git a/demos/system_admin.luash b/demos/system_admin.luash new file mode 100644 index 0000000..ae45798 --- /dev/null +++ b/demos/system_admin.luash @@ -0,0 +1,78 @@ +#!/usr/bin/env luash +-- System Administration Demo: Real-world sysadmin tasks + +print("=== System Administration with Luash ===\n") + +-- System information gathering +print("1. System Information:") +os_name = `uname -s` +architecture = `uname -m` +uptime_info = `uptime` + +print(" OS: " .. os_name) +print(" Architecture: " .. architecture) +print(" Uptime: " .. uptime_info) + +-- Process management +print("\n2. Process Management:") +process_count = `ps aux | wc -l` +print(" Total processes: " .. process_count) + +-- Check if important services are running +print("\n3. Service Status Check:") +services = {"ssh", "cron", "systemd"} +for i = 1, #services do + local service = services[i] + local result = `pgrep #{service} | wc -l` + if tonumber(result) > 0 then + print(" ✓ " .. service .. " is running") + else + print(" ✗ " .. service .. " not found") + end +end + +-- Disk usage analysis +print("\n4. Disk Usage:") +disk_usage = `df -h /` +print(" Root filesystem:") +!df -h / | tail -1 + +-- Log file analysis +print("\n5. Log Analysis:") +if `test -f /var/log/syslog && echo "exists"` == "exists" then + print(" Recent system errors:") + !tail -5 /var/log/syslog | grep -i error || echo " No recent errors found" +else + print(" Syslog not accessible (normal on macOS)") +end + +-- Network connectivity check +print("\n6. Network Check:") +hosts_to_check = {"google.com", "github.com"} +for i = 1, #hosts_to_check do + local host = hosts_to_check[i] + local ping_result = `ping -c 1 #{host} >/dev/null 2>&1 && echo "ok" || echo "fail"` + if ping_result == "ok" then + print(" ✓ " .. host .. " is reachable") + else + print(" ✗ " .. host .. " is unreachable") + end +end + +-- Generate a simple system report +print("\n7. Generating System Report:") +$REPORT_DATE = `date` +report = "System Report - " .. $REPORT_DATE .. "\n" +report = report .. "User: " .. $USER .. "\n" +report = report .. "System: " .. os_name .. " " .. architecture .. "\n" +report = report .. "Processes: " .. process_count .. "\n" + +-- Write report to file (using Lua's file operations) +local file = io.open("system_report.txt", "w") +if file then + file:write(report) + file:close() + print(" Report saved to system_report.txt") +else + print(" Failed to write report file") +end diff --git a/demos/test.luash b/demos/test.luash new file mode 100644 index 0000000..2d6e26d --- /dev/null +++ b/demos/test.luash @@ -0,0 +1,20 @@ + +-- Test environment variables +print("Current shell: " .. $SHELL) + +-- Test environment variable assignment +$HELLO = "my variable" +print("HELLO = " .. $HELLO) + +-- Test $VAR inside strings (should NOT be substituted) +print("This should print literally: $SHELL and $HOME") + +-- Test $VAR outside strings (should be substituted) +print("Home directory: " .. $HOME) + +-- Test shell commands +current_dir = `pwd` +print("Current directory: " .. current_dir) + +-- Test interactive command +!echo "Running interactive command" \ No newline at end of file diff --git a/interpolation_demo.luash b/interpolation_demo.luash new file mode 100644 index 0000000..5622947 --- /dev/null +++ b/interpolation_demo.luash @@ -0,0 +1,31 @@ +#!/usr/bin/env luash +-- Variable Interpolation Demo + +print("=== Variable Interpolation in Shell Commands ===\n") + +print("1. Basic variable interpolation:") +service = "ssh" +result = `pgrep #{service} | wc -l` +print(" Processes named '" .. service .. "': " .. result) + +print("\n2. Multiple variables in one command:") +dir = "/tmp" +pattern = "*.log" +files = `find #{dir} -name #{pattern} 2>/dev/null | wc -l` +print(" Files matching '" .. pattern .. "' in " .. dir .. ": " .. files) + +print("\n3. Network connectivity check:") +host = "google.com" +ping_result = `ping -c 1 #{host} >/dev/null 2>&1 && echo "ok" || echo "fail"` +print(" " .. host .. " is " .. (ping_result == "ok" and "reachable" or "unreachable")) + +print("\n4. Dynamic file operations:") +filename = "README.md" +if `test -f #{filename}` ~= "" then + lines = `wc -l < #{filename}` + print(" " .. filename .. " has " .. lines .. " lines") +else + print(" " .. filename .. " not found") +end + +print("\n✨ Use #{variable} syntax to substitute Lua variables into shell commands!") diff --git a/luash b/luash new file mode 100755 index 0000000..3072049 --- /dev/null +++ b/luash @@ -0,0 +1,184 @@ +#!/usr/bin/env lua +-- luash: Minimal Lua shell scripting preprocessor + +-- 1. Check for an input file +local filename = arg[1] +if not filename then + print("Usage: luash ") + return +end + +local file = io.open(filename, "r") +if not file then + print("Error: Cannot open file '" .. filename .. "'") + return +end +local source_code = file:read("*a") +file:close() + +-- Remove shebang line if present +source_code = source_code:gsub("^#![^\r\n]*[\r\n]?", "") + +-- Preprocessing functions +local function process_env_vars(code) + local lines = {} + for line in code:gmatch("([^\r\n]*)") do + if not line:match("^%s*%-%-") then -- Skip comments + + -- Handle environment variable assignment: $VAR=value + if line:match("^%$([%w_]+)%s*=") then + line = line:gsub("^%$([%w_]+)%s*=%s*(.+)", function(var, value) + return "env_set('" .. var .. "', " .. value .. ")" + end) + else + -- Handle $VAR substitution, but not inside strings + local in_string = false + local quote_char = nil + local result = "" + local i = 1 + + while i <= #line do + local char = line:sub(i, i) + + -- Track string boundaries + if (char == '"' or char == "'") and (i == 1 or line:sub(i-1, i-1) ~= "\\") then + if not in_string then + in_string = true + quote_char = char + elseif char == quote_char then + in_string = false + quote_char = nil + end + result = result .. char + i = i + 1 + elseif char == "$" and not in_string then + -- Found $ outside of string, check for variable pattern + local var_match = line:sub(i):match("^%$([%w_]+)") + if var_match then + result = result .. "env_get('" .. var_match .. "')" + i = i + #var_match + 1 + else + result = result .. char + i = i + 1 + end + else + result = result .. char + i = i + 1 + end + end + + line = result + end + end + table.insert(lines, line) + end + + return table.concat(lines, "\n") +end + +local function process_shell_commands(code) + local lines = {} + for line in code:gmatch("([^\r\n]*)") do + -- Skip processing backticks inside strings + local in_string = false + local quote_char = nil + local result = "" + local i = 1 + + while i <= #line do + local char = line:sub(i, i) + + -- Track string boundaries + if (char == '"' or char == "'") and (i == 1 or line:sub(i-1, i-1) ~= "\\") then + if not in_string then + in_string = true + quote_char = char + elseif char == quote_char then + in_string = false + quote_char = nil + end + result = result .. char + i = i + 1 + elseif char == "`" and not in_string then + -- Found backtick outside of string, find the closing backtick + local end_pos = line:find("`", i + 1) + if end_pos then + local command = line:sub(i + 1, end_pos - 1) + + -- Handle variable interpolation with #{var} syntax + if command:find("#{") then + -- Escape existing quotes first, then do interpolation + local escaped_cmd = command:gsub('"', '\\"') + local interpolated_cmd = escaped_cmd:gsub("#{([%w_.]+)}", '" .. tostring(%1) .. "') + result = result .. 'shell("' .. interpolated_cmd .. '")' + else + result = result .. 'shell("' .. command:gsub('"', '\\"') .. '")' + end + i = end_pos + 1 + else + result = result .. char + i = i + 1 + end + else + result = result .. char + i = i + 1 + end + end + + table.insert(lines, result) + end + + return table.concat(lines, "\n") +end + +local function process_interactive_commands(code) + local lines = {} + for line in code:gmatch("([^\r\n]*)") do + -- Only match ! at the beginning of the line (ignoring whitespace) + local command = line:match("^%s*!(.*)") + if command then + local indent = line:match("^(%s*)") + table.insert(lines, indent .. 'run("' .. command:gsub('"', '\\"') .. '")') + else + table.insert(lines, line) + end + end + return table.concat(lines, "\n") +end + +-- Load injected helper functions (minimal) +local injected_lib_path = debug.getinfo(1, "S").source:match("@(.*/)") or "./" +local lib_file = io.open(injected_lib_path .. "__injected_lib.lua", "r") +local injected_lib = "" +if lib_file then + injected_lib = lib_file:read("*a") + lib_file:close() +end + +-- Apply preprocessing +source_code = process_env_vars(source_code) +source_code = process_interactive_commands(source_code) +source_code = process_shell_commands(source_code) + +-- Combine and execute +local final_code = injected_lib .. "\n" .. source_code + +-- Debug output +if os.getenv("LUASH_DEBUG") then + print("-- Generated Lua code:") + print(final_code) + print("-- End generated code") +end + +-- Execute +local func, err = load(final_code, "@" .. filename) +if not func then + print("--- SYNTAX ERROR in " .. filename .. " ---") + print(err) +else + local success, result = pcall(func) + if not success then + print("--- RUNTIME ERROR in " .. filename .. " ---") + print(result) + end +end \ No newline at end of file diff --git a/showcase.luash b/showcase.luash new file mode 100644 index 0000000..9957c5a --- /dev/null +++ b/showcase.luash @@ -0,0 +1,124 @@ +#!/usr/bin/env luash +-- Luash Showcase: Highlight the best features + +print("🚀 Luash - Minimal Lua Shell Scripting") +print("=" .. string.rep("=", 45)) + +print("\n💡 Why Luash?") +print("✓ Clean syntax - no more bash quoting nightmares") +print("✓ Real programming language features") +print("✓ Seamless shell integration") +print("✓ Minimal and focused") + +print("\n📊 Quick Comparison:") +print("┌─────────────────┬─────────────────────┬─────────────────────┐") +print("│ Task │ Bash │ Luash │") +print("├─────────────────┼─────────────────────┼─────────────────────┤") +print("│ Variables │ VAR=\"value\" │ $VAR = \"value\" │") +print("│ Command Sub │ result=$(cmd) │ result = `cmd` │") +print("│ Conditionals │ if [ -f file ]; fi │ if `test -f file` │") +print("│ Arrays │ arr=(a b c) │ arr = {\"a\",\"b\",\"c\"} │") +print("│ Functions │ Limited │ Full Lua functions │") +print("└─────────────────┴─────────────────────┴─────────────────────┘") + +print("\n🎯 Live Examples:") + +print("\n1. Environment & Variables") +print(" Current user: " .. $USER) +$GREETING = "Hello from Luash" +print(" Custom var: " .. $GREETING) + +print("\n2. Shell Integration") +system_info = `uname -a` +print(" System: " .. system_info) + +file_count = `ls | wc -l` +print(" Files here: " .. file_count) + +print("\n3. Real Programming") +-- Lua's power: functions, tables, proper data types +function analyze_directory(path) + local files = `ls -la ` .. (path or ".") + local lines = {} + local file_count = 0 + local total_size = 0 + + for line in files:gmatch("[^\n]+") do + if not line:match("^total") and not line:match("^d") then + file_count = file_count + 1 + -- Extract size (5th field in ls -la) + local size = line:match("%S+%s+%S+%s+%S+%s+%S+%s+(%d+)") + if size then + total_size = total_size + tonumber(size) + end + end + end + + return file_count, total_size +end + +files, size = analyze_directory() +print(" Analysis: " .. files .. " files, " .. size .. " bytes total") + +print("\n4. Error Handling") +if `which git 2>/dev/null` ~= "" then + print(" ✓ Git is available") + if `git status 2>/dev/null` ~= "" then + branch = `git branch --show-current 2>/dev/null` + print(" Current branch: " .. branch) + else + print(" Not in a git repository") + end +else + print(" ✗ Git not installed") +end + +print("\n5. Data Processing") +-- Create and process some data +sample_data = { + {name = "Alice", score = 95}, + {name = "Bob", score = 87}, + {name = "Charlie", score = 92} +} + +total_score = 0 +for i = 1, #sample_data do + total_score = total_score + sample_data[i].score +end +average = total_score / #sample_data + +print(" Student scores processed:") +print(" Average: " .. string.format("%.1f", average)) + +-- Find highest scorer +best_student = sample_data[1] +for i = 2, #sample_data do + if sample_data[i].score > best_student.score then + best_student = sample_data[i] + end +end +print(" Top student: " .. best_student.name .. " (" .. best_student.score .. ")") + +print("\n🎪 Interactive Demo:") +print(" Let's see what's running on your system...") +!ps aux | head -5 + +print("\n📈 Performance:") +start_time = `date +%s.%N` +-- Simulate some work +for i = 1, 1000 do + local _ = string.upper("performance test " .. i) +end +end_time = `date +%s.%N` + +-- Calculate duration (requires bash-style arithmetic) +duration = tonumber(end_time) - tonumber(start_time) +print(" Processed 1000 operations in " .. string.format("%.3f", duration) .. " seconds") + +print("\n✨ Try these demos:") +print(" ./luash demo_quick_examples.luash # Side-by-side with bash") +print(" ./luash demo_system_admin.luash # Sysadmin tasks") +print(" ./luash demo_development.luash # Dev workflows") +print(" ./luash demo_data_processing.luash # Data analysis") + +print("\n🎉 Luash: Shell scripting that doesn't make you cry!") diff --git a/system_report.txt b/system_report.txt new file mode 100644 index 0000000..36ee363 --- /dev/null +++ b/system_report.txt @@ -0,0 +1,4 @@ +System Report - Fri Aug 29 00:17:34 BST 2025 +User: nik +System: Darwin arm64 +Processes: 750