BATsh チートシート [JA] 日本語
==============================

----------------------------------------------------------------------
エグゼクティブサマリー
  BATsh は cmd.exe バッチと bash/sh が同一ファイルに混在するスクリプトを
  純粋 Perl で実行するバイリンガルシェル。行単位でモードを自動判別。
  外部シェル不要。パイプ・リダイレクト・関数・変数展開拡張に対応。

混在サンプル
  :: CMD セクション（先頭トークンが大文字）
  @ECHO OFF
  SET LANG=BATsh
  SET COUNT=3

  # SH セクション（先頭トークンに小文字を含む）
  greet() { echo "こんにちは $1 (bash モード)"; }
  greet $LANG
  for i in 1 2 3; do echo "  項目 $i/$COUNT"; done
  result=$(echo $LANG | perl -ne "print uc")
  echo "大文字: $result"

  :: CMD セクション再開（SH の結果を参照）
  ECHO CMD に戻る: %result%

  # 実行: perl lib/BATsh.pm script.batsh
  # または: use BATsh; BATsh->run('script.batsh');
----------------------------------------------------------------------


BATshは、cmd.exeとbash/shの両方の構文を同一スクリプトで実行できる
バイリンガルシェルです。スクリプトはセクションに分割され、各セクションは
対応するシェルにそのまま渡されます。

1. モード判定
--------------
  セクションの最初の実質的な行の「最初のトークン」がモードを決定します。

  CMDモード: 最初のトークンが [A-Z 0-9 _ - \ / : . @ %] のみで構成され、
             かつ少なくとも1文字の大文字A-Zを含む。

    ECHO hello              -> CMDセクション (cmd.exe)
    SET FOO=bar baz         -> CMDセクション (値部分は判定しない)
    @ECHO OFF               -> CMDセクション
    IF "%X%"=="Y" (         -> CMDセクション

  SHモード: それ以外（小文字を含む、または英字がない）。

    echo hello              -> SHセクション (bash/sh)
    export FOO=bar          -> SHセクション
    if [ -f "$f" ]; then    -> SHセクション
    #!/bin/sh               -> SHセクション (シバンはSH行)

  コメントと空行は現在のセクションに吸収されます。
  コメント構文:
    ::           CMD形式コメント
    REM ...      CMD形式コメント（大文字小文字不問）
    @REM ...     CMD形式コメント
    # ...        SH形式コメント（#!シバンは除く）

2. シェルの起動
----------------
  perl lib/BATsh.pm                    # 対話型REPL
  perl lib/BATsh.pm script.batsh       # スクリプトファイルの実行
  perl lib/BATsh.pm -e "echo hi"       # インラインワンライナー

  PerlAPIから:
    use BATsh;
    BATsh->run('script.batsh');
    BATsh->run_string("echo hello");
    BATsh->repl();

3. 環境変数ブリッジ
--------------------
  各セクション実行前に、BATshは現在の%ENVをプリアンブルとして注入します
  （CMDにはSET、SHにはexport）。実行後に最終環境を%ENVに読み戻します。

  export FOO=hello   # SHがFOOをセット
  ECHO %FOO%         # CMDがブリッジ経由でFOOを参照（Windows）

  SET BAR=world      # CMDがBARをセット
  echo $BAR          # SHがブリッジ経由でBARを参照

4. SETLOCAL / ENDLOCAL
-----------------------
  SETLOCAL           # %ENVのスナップショットを保存（BATshが管理）
  SET TMP=local_val
  ECHO %TMP%
  ENDLOCAL           # %ENVを復元（TMPは消える）

  ネスト可能です。

5. セクション境界の検出
------------------------
  セクションはブロック深さが0に戻り、かつ次の実質的な行が異なるモードに
  なった時点で終了します。

  CMDセクション: 引用符外の ( と ) の深さを追跡:

    IF "%X%"=="Y" (     <- ブロック開始（深さ1）
        ECHO yes
    ) ELSE (            <- 閉じて再開（深さ>=1を維持）
        ECHO no
    )                   <- ブロック終了（深さ0）-> セクション境界

  SHセクション: キーワード深さを追跡:

    for x in 1 2; do   <- ブロック開始（深さ1）
        echo $x
    done                <- ブロック終了（深さ0）-> セクション境界

  開いたブロック内の行は、最初のトークンが他のモードに見えても
  現在のセクションに吸収されます:

    for x in A B; do
        ECHO $x         <- 大文字だがSHブロック内 -> SHセクションのまま
    done

  SHキーワード対:
    オープナー(+1): if  for  while  until  case  function  select  {
    クローザー(-1): fi  done  esac  }
    中立     ( 0): then  do  else  elif

6. サブルーチン定義
--------------------
  :GREET
  echo "Hello $BATSH_ARG1"
  RET

  ラベルは:で始まり、RETまたはRETURNで終わります。
  本体は実行前に抽出されます（インラインでは実行されません）。
  本体にはCMD行、SH行、または混合を含めることができます。

7. CALLとsource
----------------
  CALL :GREET world      # 引数付きでサブルーチンを呼び出す
  CALL other.batsh       # 別の.batshファイルをインクルード（CMD）
  source other.batsh     # 別の.batshファイルをインクルード（SH）
  . other.batsh          # POSIXのドット記法

  引数: $BATSH_ARG1 .. $BATSH_ARGn  （CMDでは %BATSH_ARG1%）
  個数: $BATSH_ARGC

8. Perl API
------------
  BATsh->run($file)            # .batshファイルを実行
  BATsh->run_string($source)   # ソース文字列を実行
  BATsh->run_lines(@lines)     # 行配列を実行
  BATsh->repl()                # 対話型REPL
  BATsh->classify_token($tok)  # 'CMD'または'SH'を返す
  BATsh->setlocal()            # %ENVをスナップショット
  BATsh->endlocal()            # %ENVを復元
  BATsh->call_sub($lbl, @args) # サブルーチンを呼び出す
  BATsh->source_file($file)    # .batshファイルをインクルード
  BATsh->version()             # バージョン文字列

9. プラットフォーム注記
------------------------
  Windows: CMDセクションもSHセクションも純粋なPerlで動作 -- 外部のcmd.exe/bash/shは不要。
  UNIX:    CMDセクションもSHセクションも純粋なPerlで動作 -- 外部のcmd.exe/bash/shは不要。

10. 動作環境
-------------
  Perl 5.005_03以降。コアモジュールのみ（File::Spec, Carp）。
  CPANの依存モジュール不要。

11. CMDパイプラインとパラメータ修飾子
--------------------------------------
  cmd1 | cmd2              # 一時ファイル経由のパイプライン（Pure Perl）
  ECHO hello | perl -e "while(<STDIN>){print uc}"

  SET /P VAR=プロンプト:   # STDINから1行読み込んでVARに格納

  バッチパラメータ修飾子（%0=C:\scripts\deploy.batの場合）:
    %~0   -> C:\scripts\deploy.bat  (クォート除去のみ)
    %~f0  -> C:/scripts/deploy.bat  (完全な絶対パス)
    %~d0  -> C:                     (ドライブ文字)
    %~p0  -> /scripts/              (ディレクトリパス)
    %~n0  -> deploy                 (拡張子なしファイル名)
    %~x0  -> .bat                   (拡張子)
    %~dp0 -> C:/scripts/            (ドライブ+ディレクトリ、最も一般的)
    %~nx1 -> deploy.bat             (名前+拡張子)

12. SH関数と変数展開
---------------------
  greet() {              # 関数定義
      echo "こんにちは $1"
  }
  function add {         # 別構文
      echo $(( $1 + $2 ))
  }
  greet world            # 関数呼び出し
  add 3 4                # -> 7

  ${var%.*}    末尾の.*に最短一致するsuffixを除去
  ${var%%.*}   末尾の.*に最長一致するsuffixを除去
  ${var#*.}    先頭の*.に最短一致するprefixを除去
  ${var##*.}   先頭の*.に最長一致するprefixを除去
  ${var/a/b}   最初のaをbに置換
  ${var//a/b}  すべてのaをbに置換
  ${var^^}     すべて大文字
  ${var,,}     すべて小文字
  ${var:2:4}   オフセット2から長さ4の部分文字列
  ${#var}      文字列長
  ${var:-def}  値があればその値、なければdef

13. SH I/Oリダイレクト
-----------------------
  cmd > file      標準出力を上書き
  cmd >> file     標準出力を追記
  cmd < file      ファイルから標準入力
  cmd 2> file     標準エラーをファイルへ
  cmd 2>&1        標準エラーを標準出力にマージ
  cmd > f 2>&1    標準出力と標準エラーを両方ファイルへ

  ヒアドキュメント（標準入力として渡す）:
    cmd <<EOF       EOFまでを本体とする。$VAR は展開される
    cmd <<'EOF'     EOFまでを本体とする。展開しない（リテラル）
    cmd <<-EOF      <<EOF と同様だが、行頭のTAB文字を除去する

14. SH複合コマンド
------------------
  cmd1 && cmd2    cmd1成功時のみcmd2実行
  cmd1 || cmd2    cmd1失敗時のみcmd2実行
  cmd1 ; cmd2     無条件でcmd2実行

参照: https://metacpan.org/dist/BATsh

