BATsh 치트시트 [KO] 한국어
==========================

----------------------------------------------------------------------
요약
  BATsh는 cmd.exe 배치와 bash/sh 구문을 같은 스크립트 파일에서 실행하는
  이중 언어 셸입니다. 줄/구역 단위로 모드를 자동 전환합니다.
  외부 셸이 필요 없습니다 -- 순수 Perl 구현.
  파이프라인, 리디렉션, 함수, 변수 확장 기능을 지원합니다.

혼합 모드 예제
  :: CMD 구역 (첫 토큰이 대문자)
  @ECHO OFF
  SET LANG=BATsh
  SET COUNT=3

  # SH 구역 (첫 토큰이 소문자)
  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 구역 (브리지를 통해 SH 결과를 읽음)
  ECHO Back in 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 _ - \ / : . @ %] 로 구성되고
            대문자 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 구역  (shebang은 SH 줄)

  주석과 빈 줄은 현재 구역에 흡수됩니다.
  주석 구문:
    ::           CMD 스타일 주석
    REM ...      CMD 스타일 주석 (대소문자 구분 없음)
    @REM ...     CMD 스타일 주석
    # ...        SH 스타일 주석  (#! shebang 아님)

2. 셸 시작하기
--------------
  perl lib/BATsh.pm               # 대화형 REPL
  perl lib/BATsh.pm script.batsh  # 스크립트 파일 실행
  perl lib/BATsh.pm -e "echo hi"  # 인라인 한 줄 명령

  Perl에서:
    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 스냅샷 (cmd.exe가 아닌 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              # 임시 파일을 통한 파이프라인 (순수 Perl)
  ECHO hello | perl -e "while(<STDIN>){print uc}"

  SET /P VAR=Prompt:       # STDIN에서 한 줄을 읽어 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 "Hi $1"
  }
  function add {         # 대체 구문
      echo $(( $1 + $2 ))
  }
  greet world            # 함수 호출
  add 3 4                # -> 7

  ${var%.*}    .* 에 일치하는 가장 짧은 접미사 제거
  ${var%%.*}   .* 에 일치하는 가장 긴   접미사 제거
  ${var#*.}    *. 에 일치하는 가장 짧은 접두사 제거
  ${var##*.}   *. 에 일치하는 가장 긴   접두사 제거
  ${var/a/b}   첫 번째 a 를 b 로 치환
  ${var//a/b}  모든 a 를 b 로 치환
  ${var^^}     전부 대문자
  ${var,,}     전부 소문자
  ${var:2:4}   오프셋 2 부터 길이 4 의 부분 문자열
  ${#var}      문자열 길이
  ${var:-def}  설정되어 있으면 그 값, 아니면 def

13. SH 입출력 리디렉션
----------------------
  cmd > file      stdout 덮어쓰기
  cmd >> file     stdout 추가
  cmd < file      파일에서 stdin
  cmd 2> file     stderr 를 파일로
  cmd 2>&1        stderr 를 stdout 에 병합
  cmd > f 2>&1    stdout 과 stderr 를 모두 파일로

  Here-document (stdin 입력):
    cmd <<EOF       EOF 까지의 본문 줄; $VAR 확장됨
    cmd <<'EOF'     EOF 까지의 본문 줄; 확장 없음 (그대로)
    cmd <<-EOF      <<EOF 와 같으나 줄 앞의 TAB 문자 제거

14. SH 복합 명령
----------------
  cmd1 && cmd2    cmd1 이 성공할 때만 cmd2 실행
  cmd1 || cmd2    cmd1 이 실패할 때만 cmd2 실행
  cmd1 ; cmd2     무조건 cmd2 실행

15. SH 배열
-----------
  arr=(a b c)            # 인덱스 배열 리터럴
  arr+=(d e)             # 요소 추가
  arr[5]=x               # 인덱스로 대입
  declare -a list        # 인덱스 배열 선언
  declare -A map         # 연관 배열 선언
  map[key]=value         # 연관 배열 대입
  map=([k1]=v1 [k2]=v2)  # 연관 배열 리터럴

  ${arr[0]}    0번 요소  ($arr 는 ${arr[0]} 와 동일)
  ${arr[-1]}   마지막 요소
  ${arr[@]}    모든 요소(단어 분리)
  ${arr[*]}    모든 요소(한 단어)
  ${#arr[@]}   요소 개수
  ${#arr[2]}   2번 요소의 길이
  ${!arr[@]}   인덱스(또는 키) 목록
  unset arr[1] # 요소 하나 삭제
  unset arr    # 배열 전체 삭제

16. SH case 문
--------------
  case $x in
      a|b|c)      echo "a, b 또는 c" ;;    # |  -- 여러 패턴
      [0-9])      echo "숫자 한 자"    ;;    # [..]  문자 클래스
      [!aeiou])   echo "자음"        ;;    # [!..] 부정 클래스
      data*)      echo "접두사"       ;;    # *  와  ?  글로빙
      "*")        echo "별표"        ;;    # 따옴표=리터럴 일치
      *)          echo "기본값"       ;;    # *)  기본 절
  esac

  절 종료자(각 본문 뒤):
    ;;    여기서 종료(일반적인 경우)
    ;&    다음 절 본문까지 이어서 실행
    ;;&   남은 패턴을 계속 검사

17. SH trap 및 시그널
---------------------
  trap 'echo bye' EXIT       # 스크립트 종료 시(또는 exit 시) 실행
  trap 'rm -f $tmp' EXIT     # 핸들러는 실행될 때 전개됨
  trap 'echo got INT' INT    # %SIG 를 통해 실제 시그널 연결
  trap '' INT                # 시그널 무시
  trap - INT                 # 기본 동작으로 복원
  trap                       # 현재 trap 목록(또는: trap -p)

  SIGSPEC: 이름(INT 또는 SIGINT), 번호(2), 또는 EXIT(= 0).
  EXIT 는 종료 시 한 번 실행; 실제 이름은 Perl %SIG 핸들러를 설치.

참고: https://metacpan.org/dist/BATsh
