Skip to content

detectShell() returns BASH when invoked from PowerShell via bash wrapper scripts #537

Description

@stalep

Summary

AeshRuntimeRunner.detectShell() incorrectly returns BASH when the CLI tool is invoked from PowerShell on macOS/Linux. This is because most CLI tools (including jbang) use a bash wrapper script to launch the JVM, and bash automatically sets BASH_VERSION in its environment. Java inherits this variable, so the detection logic hits the BASH_VERSION check before ever reaching the PSModulePath check.

Reproduction

# In PowerShell on macOS/Linux:
PS> jbang completion
# Generates bash completion instead of pwsh completion

The execution chain is:

pwsh → jbang (bash wrapper script) → bash sets BASH_VERSION → java inherits it

Root Cause

In AeshRuntimeRunner.java:716-740, the detection order is:

static ShellType detectShell() {
    if (System.getenv("FISH_VERSION") != null)   // 1st
        return ShellType.FISH;
    if (System.getenv("ZSH_VERSION") != null)    // 2nd
        return ShellType.ZSH;
    if (System.getenv("BASH_VERSION") != null)   // 3rd — hits this from pwsh!
        return ShellType.BASH;

    String shell = System.getenv("SHELL");
    if (shell == null || shell.isEmpty()) {
        if (System.getenv("PSModulePath") != null) // only as last resort
            return ShellType.PWSH;
        return null;
    }
    ...
}

BASH_VERSION is set by the bash wrapper script that launches the JVM, not by the user's shell. PSModulePath is set by PowerShell and is never set by bash/zsh/fish. But PSModulePath is only checked as a "last resort" when $SHELL is not set — which never happens on macOS/Linux.

Proposed Fix

Move the PSModulePath check before the BASH_VERSION/ZSH_VERSION/FISH_VERSION checks:

static ShellType detectShell() {
    // PSModulePath is set by PowerShell — check it first, before
    // BASH_VERSION etc. which leak from wrapper scripts
    if (System.getenv("PSModulePath") != null)
        return ShellType.PWSH;

    if (System.getenv("FISH_VERSION") != null)
        return ShellType.FISH;
    if (System.getenv("ZSH_VERSION") != null)
        return ShellType.ZSH;
    if (System.getenv("BASH_VERSION") != null)
        return ShellType.BASH;

    // Fall back to $SHELL
    String shell = System.getenv("SHELL");
    ...
}

Why this is safe: PowerShell reliably sets PSModulePath on all platforms (Windows, macOS, Linux). Unix shells (bash, zsh, fish) do not set PSModulePath. So checking it first correctly identifies the user's actual shell even when BASH_VERSION leaks from a wrapper.

Impact

Any aesh-based CLI tool that uses detectShell() (via --aesh-completion, --aesh-completion-install, or programmatic AeshRuntimeRunner.detectShell()) will misdetect PowerShell as bash on macOS/Linux when launched via a bash wrapper script.

Related

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions