NAME
BATsh::SH - Pure Perl bash/sh interpreter for BATsh
SYNOPSIS
# Used internally by BATsh; not normally called directly.
# BATsh::SH implements the SH-mode interpreter invoked when BATsh
# detects a bash/sh section in a .batsh script.
# Executed via BATsh:
use BATsh;
BATsh->run_string(<<'END');
x=hello
greet() {
echo "Hello, $1 -- ${#1} chars"
}
greet world
echo ${x^^}
for i in 1 2 3; do
echo item $i
done
ls /tmp | perl -e 'while(<STDIN>){print}'
echo out > /tmp/out.txt
END
DESCRIPTION
Executive Summary
BATsh::SH is the sh/bash interpreter component of BATsh. It handles any script section whose first token contains a lowercase letter, executing it entirely in Pure Perl -- no external shell required. It supports pipelines (|), I/O redirection (> >> 2>&1), functions, compound commands (&&/||/;), and rich parameter expansion: ${var%pat}, ${var^^}, ${var:N:L}, ${#var}.
Mixed-Mode Sample (via BATsh)
use BATsh;
BATsh->run_string(<<'SCRIPT');
:: CMD section: uppercase first token
SET CITY=Tokyo
# SH section: lowercase first token
greet() { echo "Hello from $1!"; }
greet $CITY
echo "lower: ${CITY,,}"
echo $CITY | perl -e 'while(<STDIN>){chomp;print uc,chr(10)}'
SCRIPT
FULL DESCRIPTION
BATsh::SH implements the POSIX sh / bash command set entirely in Perl. No external sh or bash is required.
Supported Features
VAR=value, export VAR=value, unset VAR
echo, printf
if/then/elif/else/fi
for VAR in list; do ... done
while condition; do ... done
until condition; do ... done
case $var in pattern) ... ;; esac
test / [ ... ] (file tests, string, integer comparisons)
cd, pwd, exit, true, false, :, read, shift, local, set
$(( arithmetic )) -- supports $1..$9 positional params
$( command substitution ), `backtick substitution`
$VAR, ${VAR}, $1..$9, $@, $*, $#, $?, $$
${VAR:-default}, ${VAR:=default}, ${VAR:+alt}
${VAR%pat}, ${VAR%%pat} -- suffix removal (shortest/longest)
${VAR#pat}, ${VAR##pat} -- prefix removal (shortest/longest)
${VAR/pat/rep}, ${VAR//pat/rep} -- substitution (first/all)
${VAR^^}, ${VAR^}, ${VAR,,}, ${VAR,} -- case conversion
${VAR:offset:length}, ${VAR:offset} -- substring
${#VAR} -- string length
source / . file
name() { ... }, function name { ... } -- function definition
cmd1 | cmd2 [| cmd3 ...] (pipeline via temporary file)
cmd1 && cmd2 (run cmd2 only if cmd1 succeeds)
cmd1 || cmd2 (run cmd2 only if cmd1 fails)
cmd1 ; cmd2 (sequential execution)
> file, >> file, < file (I/O redirection)
2> file, 2>> file (stderr redirect)
2>&1 (merge stderr into stdout)
Variable Expansion
$VAR, ${VAR}, and positional parameters $1..$9 are expanded before each line executes. $@ and $* expand to all positional parameters space-joined; $# gives their count.
The following parameter expansion forms are supported:
${VAR:-default} value if set, else default
${VAR:=default} set and use default if unset
${VAR:+alt} alt if set, else empty
${VAR%pat} remove shortest suffix matching pat
${VAR%%pat} remove longest suffix matching pat
${VAR#pat} remove shortest prefix matching pat
${VAR##pat} remove longest prefix matching pat
${VAR/pat/rep} replace first match of pat with rep
${VAR//pat/rep} replace all matches of pat with rep
${VAR^^} convert to uppercase
${VAR^} uppercase first character
${VAR,,} convert to lowercase
${VAR,} lowercase first character
${VAR:N:L} substring from offset N, length L
${VAR:N} substring from offset N to end
${#VAR} length of value
Patterns use shell glob syntax: * matches any string, ? matches any single character, [abc] matches a character class.
Function Definitions
Shell functions are defined with name() { ... } or function name { ... }. Inline single-line bodies are also supported: name() { cmd; }. Functions receive arguments as $1..$9 and $@. The caller's positional parameters are saved before the call and restored on return.
Pipeline
The | operator is supported in SH mode. The left side's standard output is written to a temporary file (File::Spec->tmpdir()), which is then fed as standard input to the right side. Multiple pipes (cmd1 | cmd2 | cmd3) are handled by chaining temporary files. All temporary files are removed after use. This implementation is Pure Perl and Perl 5.005_03 compatible.
I/O Redirection
cmd > file stdout overwrite (create or truncate)
cmd >> file stdout append
cmd < file stdin from file
cmd 2> file stderr overwrite
cmd 2>> file stderr append
cmd 2>&1 merge stderr into stdout (current stdout target)
cmd 1>&2 merge stdout into stderr
Redirections are parsed after variable expansion, so filenames may contain variables (e.g. echo text > $outfile). All file handles use bareword globs for Perl 5.005_03 compatibility.
Compound Commands
cmd1 && cmd2 run cmd2 only if cmd1 exits with status 0
cmd1 || cmd2 run cmd2 only if cmd1 exits with non-zero status
cmd1 ; cmd2 run cmd2 unconditionally after cmd1
These are detected before variable expansion to ensure short-circuit logic works correctly. Quoting (', ") and $(...) nesting are respected when splitting.
Function Definitions
name() { body }
function name { body }
name() { cmd1; cmd2; } # inline single-line body
Functions are registered in a package-level hash %_SH_FUNCTIONS. The caller's positional parameters ($1..$9, $*) are saved before the call and restored on return. local VAR=value saves the existing value of VAR in the function's stack frame and restores it on return.
AUTHOR
INABA Hitoshi <ina@cpan.org>
LICENSE
Same as Perl itself.