BATsh

 view release on metacpan or  search on metacpan

lib/BATsh.pm  view on Meta::CPAN

  # Perl 5.005_03 and later; pure-Perl, no external shell required.

=head1 DESCRIPTION

=head2 Executive Summary

BATsh is a bilingual shell interpreter written in pure Perl.
It runs cmd.exe batch syntax and bash/sh syntax in the B<same script file>,
switching automatically between CMD mode and SH mode on a line-by-line basis.
No external cmd.exe, bash, or sh is required -- everything runs inside Perl.

=head2 Mixed-Mode Sample

The following script demonstrates cmd.exe and bash sections coexisting and
sharing variables through the common BATsh::Env variable store.

  :: -- CMD section: sets a variable and calls a SH function via bridge --
  @ECHO OFF
  SET LANG=BATsh
  SET COUNT=3

  # -- SH section: reads CMD variables, uses functions and pipeline --
  greet() {
      echo "Hello from $1 (bash/sh mode)"
  }
  greet $LANG
  for i in 1 2 3; do echo "  item $i of $COUNT"; done
  result=$(echo "$LANG" | perl -ne "print uc")
  echo "Uppercase: $result"
  echo "log line" >> /tmp/batsh_demo.txt

  :: -- CMD section again: reads variable set by SH side --
  ECHO Back in CMD mode
  ECHO Uppercase result: %result%

BATsh features (both modes): pipelines (|), I/O redirection (> >> < 2>&1),
variable expansion (${var%pat} ${var^^} ${#var}), functions, shift, local.

=head1 FULL DESCRIPTION

BATsh is a bilingual shell interpreter written in pure Perl.
It implements both the cmd.exe command set and the sh/bash command set
entirely in Perl -- no external cmd.exe, bash, or sh is required.

Scripts are divided into CMD sections (uppercase first token) and SH sections
(lowercase first token). Both sections share a common variable store via
BATsh::Env, so variables set in a CMD section are immediately visible in the
next SH section and vice versa.

=head1 CMD MODE

Any line whose first token is all uppercase (A-Z, 0-9, path chars) is a CMD
line. CMD sections are executed by BATsh::CMD, which implements:

  ECHO, @ECHO OFF/ON
  SET VAR=value, SET /A expr (arithmetic)
  SET /P VAR=Prompt  (interactive prompt input from STDIN)
  IF "A"=="B" ... ELSE ..., IF /I (case-insensitive), IF NOT
  IF EXIST "path with spaces", IF DEFINED var, IF ERRORLEVEL n
  FOR %%V IN (list) DO ..., FOR /L %%V IN (s,step,e) DO ...
  FOR /F "tokens= delims= skip= eol= usebackq" %%V IN (src) DO ...
  GOTO :label, :label, GOTO :EOF
  CALL :label [args], CALL file.batsh
  SHIFT, SHIFT /N
  SETLOCAL [ENABLEDELAYEDEXPANSION|DISABLEDELAYEDEXPANSION], ENDLOCAL
  CD, DIR, COPY, DEL, MOVE, MKDIR, RMDIR, REN, TYPE
  PAUSE, EXIT [/B] [code], CLS, TITLE, VER, PUSHD, POPD
  cmd1 | cmd2  (pipeline via temporary file)
  &, &&, ||  (sequential, conditional-and, conditional-or)

=head2 Variable Expansion

C<%VAR%> references are expanded before each line is dispatched.
Variable names are B<case-insensitive> (C<SET foo=x> is visible as C<%FOO%>).

Inside parenthesised IF and FOR blocks, C<%VAR%> is expanded B<at parse time>
(before any commands in the block run), matching cmd.exe behaviour.  To see
a value updated inside a block, use delayed expansion:

  SETLOCAL ENABLEDELAYEDEXPANSION
  SET X=old
  IF 1==1 (
      SET X=new
      ECHO !X!       &:: prints "new" (delayed)
      ECHO %X%       &:: prints "old" (parse-time)
  )
  ENDLOCAL

=head2 Batch Parameters

C<%0> is the script path (absolute); C<%1>..C<%9> are positional arguments;
C<%*> is all arguments joined by space.

C<CALL :label arg1 arg2 ...> invokes a subroutine as a true call frame: the
subroutine receives its own C<%0> (the C<:label> token), C<%1>..C<%9> (the
call arguments) and C<%*> (their join), and the caller's parameters are
saved before the call and restored on return.  Arguments are C<%>-expanded
before the call and split with double-quote awareness, so
C<CALL :sub "a b" %FILE%> passes C<a b> as one argument and the expanded
value of C<%FILE%> as the next.  Nested calls each get an independent frame.
The same arguments are also visible as C<$1>..C<$9> / C<$@> when the
subroutine body is written in SH mode.

C<SHIFT> moves C<%2> into C<%1>, C<%3> into C<%2>, and so on, clears C<%9>,
and rebuilds C<%*>; C<SHIFT /N> begins the shift at C<%N> (C<%1>..C<%(N-1)>
are left unchanged).

Batch-parameter tilde modifiers expand C<%0>..C<%9> components:

  %~0    dequote (strip surrounding "...")
  %~f1   full absolute path of %1
  %~d1   drive letter only   (e.g. C:)
  %~p1   directory path only (with trailing /)
  %~n1   filename without extension
  %~x1   extension only       (e.g. .bat)
  %~dp0  drive + directory    (most common usage)
  %~nx1  filename + extension

=head2 Redirection and Compound Commands

  ECHO text > file      stdout overwrite



( run in 1.647 second using v1.01-cache-2.11-cpan-acf6aa7dc9e )