BATsh
view release on metacpan or search on metacpan
lib/BATsh.pm view on Meta::CPAN
%~dp0 drive + directory (most common usage)
%~nx1 filename + extension
=head2 Redirection and Compound Commands
ECHO text > file stdout overwrite
ECHO text >> file stdout append
prog 2> err.txt stderr redirect
& cmd sequential execution
cmd1 && cmd2 run cmd2 only if cmd1 succeeded (ERRORLEVEL 0)
cmd1 || cmd2 run cmd2 only if cmd1 failed (ERRORLEVEL != 0)
The C<^> character escapes the next character:
ECHO a^&b prints a&b (& not treated as compound separator)
ECHO a^^b prints a^b
ECHO text^ next line is joined (line continuation)
=head1 SH MODE
Any line whose first token contains a lowercase letter is a SH line.
SH sections are executed by BATsh::SH, which implements:
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 pat1|pat2) ... ;; *) ... ;; esac
(|-patterns, * ? [abc] [a-z] [!abc] globs, ;& and ;;& fall-through)
test / [ ... ] (file, string, and integer comparisons)
cd, pwd, exit, true, false, :, read, shift [N], local VAR=value
trap 'cmd' SIG... / trap - SIG / trap '' SIG / trap [-p] (EXIT + %SIG)
$(( arithmetic )) -- +, -, *, /, %, and $1..$9 inside
$( command ) and `command` (command substitution, nested)
cmd1 | cmd2 [| cmd3 ...] (pipeline via temporary file)
cmd1 && cmd2, cmd1 || cmd2, cmd1 ; cmd2 (compound commands)
> >> < 2> 2>> 2>&1 1>&2 (I/O redirection)
name() { ... }, function name { ... } (function definitions)
$VAR, ${VAR}, $1..$9, $@, $*, $#, $?, $$, $0
${VAR:-default}, ${VAR:=default}, ${VAR:+alt}
${VAR%pat}, ${VAR%%pat} -- shortest/longest suffix removal
${VAR#pat}, ${VAR##pat} -- shortest/longest prefix removal
${VAR/pat/rep}, ${VAR//pat/rep} -- first/all substitution
${VAR^^}, ${VAR^}, ${VAR,,}, ${VAR,} -- case conversion
${VAR:N:L}, ${VAR:N} -- substring
${#VAR} -- string length
arr=(a b c), arr+=(d e), arr[i]=v, arr[i]+=v -- indexed arrays
declare -a arr, declare -A map, typeset ... -- array declaration
map=([k]=v ...), map[k]=v -- associative arrays
${arr[i]}, ${map[key]}, $arr (== ${arr[0]}) -- element access
${arr[@]}, ${arr[*]}, ${#arr[@]}, ${#arr[i]}, ${!arr[@]}
unset arr, unset arr[i]
source / . file
=head1 REQUIREMENTS
Perl 5.005_03 or later. Core modules only. No external shell required.
=head1 BUGS AND LIMITATIONS
Commands that are not built in -- C<FINDSTR>, C<SORT>, C<MORE>, C<CHOICE>,
C<TIMEOUT>, C<XCOPY>, C<ROBOCOPY> and the like in CMD mode, and any
non-builtin program in SH mode -- are B<not> reimplemented in Perl. They
are invoked as external programs (via Perl's C<system>), so they work only
where the host operating system provides the corresponding executable
(e.g. F<FINDSTR.EXE> on Windows). This is by design: only the built-in
command set is guaranteed to run identically on every platform.
The built-in CMD interpreter does not implement:
=over
=item * C<FOR /F> with C<usebackq> backtick-quoted commands on Windows
(the C<cmd /c> subprocess path is untested on Windows).
=back
Variable substring C<%VAR:~n,m%> / C<%VAR:~n%> / C<%VAR:~-n%> / C<%VAR:~n,-m%>
and in-place substitution C<%VAR:str1=str2%> / C<%VAR:*str1=str2%> are B<now
supported> as of version 0.05 (see L<BATsh::Env>).
Dynamic pseudo-variables C<%DATE%> (YYYY-MM-DD), C<%TIME%> (HH:MM:SS.cc),
C<%CD%> (current directory), C<%RANDOM%> (0-32767), C<%ERRORLEVEL%>, and
C<%CMDCMDLINE%> are B<now supported> as of version 0.05.
Indexed and associative arrays -- C<arr=(a b c)>, C<arr+=(...)>,
C<arr[i]=v>, C<declare -A map>, C<map=([k]=v ...)>, C<${arr[i]}>,
C<${arr[@]}>, C<${#arr[@]}>, C<${!arr[@]}>, and C<unset arr[i]> -- are
B<now supported> as of version 0.06 (see L<BATsh::SH>). Element ordering
for C<${arr[@]}> is ascending numeric index for indexed arrays and sorted
key order for associative arrays (bash leaves the latter unspecified);
C<"${arr[@]}"> word-splits to one item per element in C<for> lists.
The built-in SH interpreter does not implement:
=over
=item * Tilde expansion C<~/path> and C<~user> (only C<cd> with no
argument uses C<$HOME>).
=item * Brace expansion C<{a,b}> and C<{1..5}>.
=item * Here-strings (C<E<lt>E<lt>E<lt> word>) and process substitution
(C<E<lt>(cmd)>, C<E<gt>(cmd)>).
=item * The shell options C<set -e>, C<set -u>, C<set -x>, and the
builtins C<getopts>, C<select>, C<alias>, C<eval> and C<exec>.
=back
C<trap> B<is> supported in SH mode: C<trap 'cmd' SIGSPEC...> registers a
handler, C<trap - SIGSPEC> resets to default, C<trap '' SIGSPEC> ignores,
and C<trap> / C<trap -p> lists. Real signals are bridged to Perl's C<%SIG>;
the C<EXIT> pseudo-signal (also C<0>) runs when the script ends or on
C<exit>. The handler is expanded when it fires. See L<BATsh::SH/"Traps and
Signals">.
Common to both modes: a parenthesised group C<( ... )> does not run in a
separate sub-shell; it shares the one variable store, so there is no
( run in 0.846 second using v1.01-cache-2.11-cpan-0b5f733616e )