wow
This commit is contained in:
328
README.md
Normal file
328
README.md
Normal file
@@ -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.
|
||||
38
SPEC.md
Normal file
38
SPEC.md
Normal file
@@ -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}")
|
||||
```
|
||||
33
__injected_lib.lua
Normal file
33
__injected_lib.lua
Normal file
@@ -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
|
||||
75
demo_quick_examples.luash
Normal file
75
demo_quick_examples.luash
Normal file
@@ -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!")
|
||||
40
demos/basic.luash
Normal file
40
demos/basic.luash
Normal file
@@ -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")
|
||||
158
demos/data_processing.luash
Normal file
158
demos/data_processing.luash
Normal file
@@ -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!")
|
||||
126
demos/development.luash
Normal file
126
demos/development.luash
Normal file
@@ -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!")
|
||||
75
demos/quick_examples.luash
Normal file
75
demos/quick_examples.luash
Normal file
@@ -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!")
|
||||
47
demos/run_demo.luash_
Normal file
47
demos/run_demo.luash_
Normal file
@@ -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!")
|
||||
124
demos/showcase.luash
Normal file
124
demos/showcase.luash
Normal file
@@ -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!")
|
||||
78
demos/system_admin.luash
Normal file
78
demos/system_admin.luash
Normal file
@@ -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
|
||||
20
demos/test.luash
Normal file
20
demos/test.luash
Normal file
@@ -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"
|
||||
31
interpolation_demo.luash
Normal file
31
interpolation_demo.luash
Normal file
@@ -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!")
|
||||
184
luash
Executable file
184
luash
Executable file
@@ -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 <script.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
|
||||
124
showcase.luash
Normal file
124
showcase.luash
Normal file
@@ -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!")
|
||||
4
system_report.txt
Normal file
4
system_report.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
System Report - Fri Aug 29 00:17:34 BST 2025
|
||||
User: nik
|
||||
System: Darwin arm64
|
||||
Processes: 750
|
||||
Reference in New Issue
Block a user