BATsh Cheat Sheet [EN] English
==============================

----------------------------------------------------------------------
EXECUTIVE SUMMARY
  BATsh is a bilingual shell that runs cmd.exe batch and bash/sh syntax
  in the same script file. It switches modes automatically per line/section.
  No external shell needed -- pure Perl implementation.
  Supports pipelines, redirection, functions, and variable-expansion extensions.

MIXED-MODE SAMPLE
  :: CMD section (uppercase first token)
  @ECHO OFF
  SET LANG=BATsh
  SET COUNT=3

  # SH section (lowercase first token)
  greet() { echo "Hello from $1 (bash 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"

  :: CMD section again (reads SH result via bridge)
  ECHO Back in CMD: %result%

  # Run with: perl lib/BATsh.pm script.batsh
  # Or:       use BATsh; BATsh->run('script.batsh');
----------------------------------------------------------------------


BATsh is a bilingual shell that runs cmd.exe and bash/sh syntax in the
same script.  The script is divided into sections; each section is
executed verbatim by the appropriate shell.

1. Mode Detection
-----------------
  The FIRST TOKEN of the first substantive line of a section determines
  which shell executes that section:

  CMD mode: first token is entirely [A-Z 0-9 _ - \ / : . @ %]
            AND contains at least one uppercase letter A-Z.

    ECHO hello          -> CMD section (cmd.exe)
    SET FOO=bar baz     -> CMD section  (value part not tested)
    @ECHO OFF           -> CMD section
    IF "%X%"=="Y" (     -> CMD section

  SH mode: anything else (any lowercase letter, or no letter at all).

    echo hello          -> SH section  (bash/sh)
    export FOO=bar      -> SH section
    if [ -f "$f" ]; then  -> SH section
    #!/bin/sh           -> SH section  (shebang is a SH line)

  Comments and blank lines are absorbed into the current section.
  Comment syntax:
    ::           CMD-style comment
    REM ...      CMD-style comment (case-insensitive)
    @REM ...     CMD-style comment
    # ...        SH-style comment  (NOT #! shebang)

2. Starting the Shell
----------------------
  perl lib/BATsh.pm               # interactive REPL
  perl lib/BATsh.pm script.batsh  # run a script file
  perl lib/BATsh.pm -e "echo hi"  # inline one-liner

  From Perl:
    use BATsh;
    BATsh->run('script.batsh');
    BATsh->run_string("echo hello");
    BATsh->repl();

3. Environment Variable Bridge
--------------------------------
  Before each section runs, BATsh injects the current %ENV as preamble
  (SET lines for CMD, export lines for SH).  After the section, the
  shell's final environment is read back into %ENV.

  export FOO=hello   # SH sets FOO
  ECHO %FOO%         # CMD reads FOO via bridge (Windows)

  SET BAR=world      # CMD sets BAR
  echo $BAR          # SH reads BAR via bridge

4. SETLOCAL / ENDLOCAL
-----------------------
  SETLOCAL           # snapshot %ENV (handled by BATsh, not cmd.exe)
  SET TMP=local_val
  ECHO %TMP%
  ENDLOCAL           # restore %ENV (TMP is gone)

  Scopes may be nested.

5. Section Boundary Detection
------------------------------
  A section ends when its block depth returns to zero AND the next
  substantive line belongs to a different mode.

  CMD sections track unquoted ( and ) depth:

    IF "%X%"=="Y" (     <- opens block (depth 1)
        ECHO yes
    ) ELSE (            <- closes and reopens (depth stays >=1)
        ECHO no
    )                   <- closes block (depth 0) -> section may end

  SH sections track keyword depth:

    for x in 1 2; do   <- opens block (depth 1)
        echo $x
    done                <- closes block (depth 0) -> section may end

  Lines inside an open block are absorbed into the current section even
  if their first token looks like the other mode.  This allows:

    for x in A B; do
        ECHO $x          <- uppercase inside SH block: still SH section
    done

  SH keyword pairs:
    Openers (+1): if  for  while  until  case  function  select  {
    Closers (-1): fi  done  esac  }
    Neutral ( 0): then  do  else  elif

6. Subroutine Definitions
--------------------------
  :GREET
  echo "Hello $BATSH_ARG1"
  RET

  Labels begin with : and end with RET or RETURN.
  The body is extracted before execution (not run inline).
  The body may contain CMD lines, SH lines, or a mixture.

7. CALL and source
-------------------
  CALL :GREET world      # call subroutine with argument
  CALL other.batsh       # include/run another .batsh file (CMD)
  source other.batsh     # include/run another .batsh file (SH)
  . other.batsh          # POSIX dot notation

  Arguments: $BATSH_ARG1 .. $BATSH_ARGn  (%BATSH_ARG1% in CMD)
  Count:     $BATSH_ARGC

8. Perl API
------------
  BATsh->run($file)            # run a .batsh file
  BATsh->run_string($source)   # run source string
  BATsh->run_lines(@lines)     # run array of lines
  BATsh->repl()                # interactive REPL
  BATsh->classify_token($tok)  # 'CMD' or 'SH'
  BATsh->setlocal()            # snapshot %ENV
  BATsh->endlocal()            # restore %ENV
  BATsh->call_sub($lbl, @args) # call subroutine
  BATsh->source_file($file)    # include .batsh file
  BATsh->version()             # version string

9. Platform Notes
------------------
  Windows: Both CMD and SH sections run in pure Perl -- no external cmd.exe, bash, or sh needed.
  UNIX:    Both CMD and SH sections run in pure Perl -- no external cmd.exe, bash, or sh needed.

10. Requirements
-----------------
  Perl 5.005_03 or later.  Core modules only (File::Spec, Carp).
  No CPAN dependencies.

11. CMD Pipeline and Parameter Modifiers
-----------------------------------------
  cmd1 | cmd2              # pipeline via temporary file (Pure Perl)
  ECHO hello | perl -e "while(<STDIN>){print uc}"

  SET /P VAR=Prompt:       # read a line from STDIN into VAR

  Batch-parameter tilde modifiers (e.g. when %0=C:\scripts\deploy.bat):
    %~0   -> C:\scripts\deploy.bat  (dequote only)
    %~f0  -> C:/scripts/deploy.bat  (full absolute path)
    %~d0  -> C:                     (drive letter)
    %~p0  -> /scripts/              (directory path)
    %~n0  -> deploy                 (filename without extension)
    %~x0  -> .bat                   (extension)
    %~dp0 -> C:/scripts/            (drive + directory, most common)
    %~nx1 -> deploy.bat             (name + extension)

12. SH Functions and Expansion
--------------------------------
  greet() {              # function definition
      echo "Hi $1"
  }
  function add {         # alternative syntax
      echo $(( $1 + $2 ))
  }
  greet world            # call function
  add 3 4                # -> 7

  ${var%.*}    remove shortest suffix matching .*
  ${var%%.*}   remove longest  suffix matching .*
  ${var#*.}    remove shortest prefix matching *.
  ${var##*.}   remove longest  prefix matching *.
  ${var/a/b}   replace first  occurrence of a with b
  ${var//a/b}  replace all    occurrences of a with b
  ${var^^}     uppercase all
  ${var,,}     lowercase all
  ${var:2:4}   substring from offset 2, length 4
  ${#var}      string length
  ${var:-def}  value if set, else def

13. SH I/O Redirection
------------------------
  cmd > file      stdout overwrite
  cmd >> file     stdout append
  cmd < file      stdin from file
  cmd 2> file     stderr to file
  cmd 2>&1        merge stderr into stdout
  cmd > f 2>&1    both stdout and stderr to file

  Here-documents (input on stdin):
    cmd <<EOF       body lines until EOF; $VAR expanded
    cmd <<'EOF'     body lines until EOF; no expansion (literal)
    cmd <<-EOF      as <<EOF, but leading TAB characters stripped

14. SH Compound Commands
-------------------------
  cmd1 && cmd2    run cmd2 only if cmd1 succeeds
  cmd1 || cmd2    run cmd2 only if cmd1 fails
  cmd1 ; cmd2     run cmd2 unconditionally

See also: https://metacpan.org/dist/BATsh

