BATsh

 view release on metacpan or  search on metacpan

Changes  view on Meta::CPAN

  - POD updated: BATsh.pm BUGS AND LIMITATIONS now records that
    %VAR:~n,m% / %VAR:str1=str2% and all dynamic pseudo-variables are
    supported; the SH filename-globbing limitation item is removed.
    BATsh::Env Variable Expansion section documents all new forms.
    BATsh::SH Supported Features table lists glob expansion.

  - Version bumped to 0.05 in lib/BATsh.pm, lib/BATsh/CMD.pm,
    lib/BATsh/SH.pm, lib/BATsh/Env.pm, Makefile.PL, META.yml,
    META.json, and README.

  - created by INABA Hitoshi

0.04  2026-06-07 JST (Japan Standard Time)

  - Inline-Perl portability: every shelled-out Perl one-liner in the
    distribution is rewritten into a form that satisfies BOTH external
    shells that BATsh dispatches to -- cmd.exe (system STRING on Win32)
    and /bin/sh -c (system STRING on Unix/BSD). The previous forms hit
    two distinct, OS-specific foot-guns:
      (A) Unix: a dollar token inside the code (e.g. "$_") was expanded
          by /bin/sh from the environment variable "_" (the last-arg /
          path that the shell exports), which is unpredictable on CPAN
          smokers and produced random failures such as
          "Bareword found where operator expected ... 1EERDtQcrK".
      (B) Win32: cmd.exe does not honour single quotes, so a one-liner
          wrapped in '...' was split on whitespace and Perl died with
          "Can't find string terminator".
    The portable form uses DOUBLE quotes and no shell-expandable dollar
    token, e.g.  perl -e "..."  ->  perl -ne "print uc"  (the default
    variable is consumed implicitly by uc, so nothing leaks to the
    shell). Rewritten in: lib/BATsh.pm POD, lib/BATsh/SH.pm POD, README,
    all 21 doc/batsh_cheatsheet.*.txt files, eg/05_cmd_comprehensive.batsh,
    eg/06_sh_comprehensive.batsh, and t/0006-new-features.t. The stderr
    sample in eg/06_sh_comprehensive.batsh is likewise switched from a
    single-quoted body to a double-quoted "print STDERR qq(...)" form.

  - t/0007-extcmd-env.t: new regression test that locks in the
    portability fix above. EE01/EE02 run the pipeline and here-document
    patterns under several hostile values of the environment variable
    "_" and confirm correct uppercase output (this passes on every OS
    and actively defeats vector (A) on Unix). EE03 is the clean-
    environment baseline. EE04 is a static guard against vector (B):
    no inline "perl -e/-ne/-pe" anywhere in t/ eg/ doc/ lib/ README may
    be wrapped in single quotes. EE05 is a static guard against vector
    (A): no double-quoted inline Perl may contain a shell-expandable
    dollar token ($name, $_, ${...}, $1..$9); the harmless numeric $$
    is exempt. Both static guards run on any OS, so a Windows run still
    catches a Unix-introduced regression and vice versa. Added to
    MANIFEST.

  - External-Perl PATH portability (vector C): the test suite and the
    eg/ examples shell out to a bareword "perl", but a CPAN smoker
    frequently does NOT have the perl under test on PATH as "perl"
    (perlbrew/plenv, or perl invoked by absolute path). The bareword
    then resolves to nothing ("perl: not found", empty output), which
    failed t/0007 EE01/EE02 and t/0006 NF23/NF60 and -- worse -- let
    t/0006 NF07/NF21/NF22 report a corrupted, empty-named "ok" when the
    failed pipe disturbed the captured-STDOUT save/restore; in eg/06 it
    also hung (an empty "perl" command substitution fed a
    "while read ... < $EMPTY" redirect whose read fell back to terminal
    STDIN and blocked). Fixed WITHOUT touching the command strings or
    the examples (a bareword "perl" is the correct thing for an end
    user to type, and embedding an absolute $^X path would expose a
    Win32 backslash path to SH-mode quote/escape processing): each
    affected test now prepends the directory of the running interpreter
    ($^X) to PATH so the bareword "perl" resolves to the very perl now
    running the suite. The prepend is installed before the first
    BATsh::Env::init() (init() snapshots %ENV into STORE and
    sync_to_env() copies STORE back to %ENV before each external
    command). Touched: t/0006-new-features.t, t/0007-extcmd-env.t,
    t/9070-examples.t (the last for the eg/ child process). Verified on
    Linux with perl deliberately removed from the child PATH (and under
    a hostile "_"): all 606 tests pass, no failures, no hangs; the
    command strings and all eg/*.batsh examples are byte-for-byte
    unchanged.

  - t/0006-new-features.t: the END block now sets "$? = 1 if $fail"
    instead of calling "exit 1", matching the INA_CPAN_Check.pm END-block
    convention adopted in 0.03 (an END block must not call exit, so that
    the harness sees the real plan/ok reconciliation).

  - Documentation: the "self-contained" qualifier is removed from
    lib/BATsh.pm (header comment, module description, the run() banner,
    and the NAME / DESCRIPTION POD) and from README. BATsh dispatches
    external commands to a real shell, so describing the interpreter
    itself as "self-contained" was misleading; "bilingual shell
    interpreter written in pure Perl" is retained and accurate.

  - SH nested command substitution fixed (lib/BATsh/SH.pm). $( ... )
    has been advertised as supporting full nesting since 0.02, but a
    nested $( ... $( ... ) ) -- especially with a pipeline at each
    level -- collapsed to an empty string, and on Unix a nested
    pipeline could hang; the failure mode also differed between Windows
    and Unix. Three independent defects were responsible:
      (1) _cmd_subst() named its stdout-capture temp file with the
          process id alone (batsh_cap_$$.tmp). An inner $(...) reused
          the same path and unlink()'d it, so the outer level captured
          nothing. The capture file is now tagged with the active
          substitution-nesting depth.
      (2) _split_sh_pipe() counted the "(" of a "$(" twice, leaving the
          $( nesting depth stuck at 1 after a nested $(...); a bare "|"
          that followed it was then not recognised as a pipe. "$(" now
          consumes both characters and bumps the depth exactly once.
      (3) _exec_sh_pipe() named its per-stage temp files with the
          process id alone (batsh_shp_$$) and left its dup STDOUT/STDIN
          globs un-local()ised. A nested pipeline therefore clobbered
          the outer pipeline's stage file and saved handles; the outer's
          final segment found no input file and blocked on the real
          STDIN (a hang on Unix). The stage files are now tagged with
          the active pipeline-nesting depth and the handle globs are
          local()ised. All fixes are Perl 5.005_03 compatible (use vars
          package globals, bareword filehandles, 2-argument open). The
          command strings and the externally-visible API are unchanged.

  - t/0008-nested-subst.t: new regression test for the fix above. NS01/
    NS02 prove the capture-file depth fix with pure builtins (no "perl"
    on PATH required); NS03 is the single-level pipeline-in-$() baseline;
    NS04/NS05 cover nested $() with a pipeline at each level (defects 2
    and 3); NS06 checks that two sibling $() pipelines on one line do
    not collide; NS07 covers an assignment from a nested pipeline
    substitution and its reuse. Like t/0006/0007 it prepends the running
    interpreter's directory to PATH so the bareword "perl" resolves on a
    smoker. Added to MANIFEST.

  - eg/05_cmd_comprehensive.batsh: the SET/IF demonstration variable was
    renamed LANG -> GREETING. As LANG, the example exported LANG=BATsh
    into %ENV, and the external "perl" it later spawns then emitted a
    glibc "Setting locale failed ... LANG = BATsh" warning to STDERR on
    Unix (harmless, and invisible during "make test" because
    t/9070-examples.t captures and discards child STDERR, but visible
    when the example is run by hand; Windows perl does not warn). The
    rename keeps the example's behaviour identical and silences the
    Unix-only noise.

  - eg/00_hello.pl: normalised from a CRLF line ending to LF, matching
    the rest of eg/ (the other examples are already LF). Perl tolerates
    the trailing CR on Unix, so this is a cosmetic consistency fix.

  - Version bumped to 0.04 in lib/BATsh.pm, lib/BATsh/CMD.pm,
    lib/BATsh/SH.pm, lib/BATsh/Env.pm, Makefile.PL, META.yml and
    META.json. BATsh::CMD and BATsh::Env carry no changes other than
    the version; BATsh::SH changes are the version, the two POD
    one-liner rewrites noted above, and the nested command-substitution
    fix noted above.

  - created by INABA Hitoshi

0.03  2026-06-06 JST (Japan Standard Time)

  - t/lib/INA_CPAN_Check.pm: emit exactly one TAP plan line per test
    file. Each check_* helper previously called plan_tests() itself,
    while the .t files also called plan_tests(count_*); this produced
    multiple "1..N" lines in a single file. Under a real TAP harness
    (prove / Test::Harness, as used by CPAN Testers) this raised
    "More than one plan found in TAP output" and made the affected
    files FAIL, even though every individual "ok" line passed when the
    scripts were run by hand. Affected files: t/9010-encoding.t,
    t/9030-distribution.t, t/9040-style.t. The plan_tests() call is
    now removed from every check_* helper, leaving the .t file as the
    sole owner of the plan line.
  - t/lib/INA_CPAN_Check.pm: count_A() now returns the actual number
    of MANIFEST entries instead of a fixed 1, so that the plan
    computed by t/9030-distribution.t matches the number of A1 checks
    that check_A() emits.
  - t/lib/INA_CPAN_Check.pm: remove the mid-stream plan_skip() calls
    from check_A() and check_C(); the MANIFEST-absent guard is handled
    by the .t file and by count_C() before any plan line is printed.
  - t/lib/INA_CPAN_Check.pm: check_K() now honours the k3_exempt



( run in 1.487 second using v1.01-cache-2.11-cpan-800906f7e73 )