Shells

Each shell represents a command-line interpreter, and is associated with:

  • a unique shell ID

  • a human-readable name

  • an icon (emoji / unicode character)

  • a detection function

  • various metadata in its info() method

Shell usage

Each shell is materialized by a Shell object, from which you can access various metadata:

>>> from extra_platforms import BASH
>>> BASH
Shell(id='bash', name='Bash')
>>> BASH.id
'bash'
>>> BASH.current
False
>>> BASH.info()
{'id': 'bash', 'name': 'Bash', 'icon': '#', 'url': 'https://www.gnu.org/software/bash/', 'current': False, 'version': None, 'path': None}

To check if the current environment is running in a specific shell, use the corresponding detection function:

>>> from extra_platforms import is_bash
>>> is_bash()
False

The current shell can be obtained via the current_shell() function:

>>> from extra_platforms import current_shell
>>> current_shell()
Shell(id='unknown_shell', name='Unknown shell')

The path to the running shell’s executable is available via current_shell_path(). It prefers the actual ancestor process binary (read from /proc on Linux, ps on macOS and the BSDs) over the SHELL environment variable, so it stays accurate when SHELL is unset or points to a different shell than the one executing.

Multiple shells can match at once

Shell detection functions are independent heuristics. Each one reads three channels in turn:

  1. A version environment variable that only the shell itself sets on startup (like FISH_VERSION).

  2. The SHELL environment variable: the configured login shell, resolved through symlinks as described above.

  3. The parent process tree (read from /proc on Linux, ps on macOS and the BSDs, the Win32 API on Windows): the shells actually running as ancestors of the current process.

These channels describe different things, so several detection functions can legitimately return True at the same time:

  • The login shell differs from the running shell: a fish user running a bash script is detected by both is_fish() (from SHELL) and is_bash() (from the process tree).

  • Shells nest: a build chroot driven from a fish terminal keeps fish in the ancestor tree, above the bash chain running the build, and both are real ancestor processes.

  • PowerShell modifies PSModulePath on startup and every child process inherits it, so is_powershell() can stay True alongside the shell really executing your code. This is a permanent fixture of GitHub Ubuntu runners, where the variable leaks from the Azure infrastructure.

An is_*() function therefore answers “is this shell part of the current environment?”, not “is this the shell executing me?”. For the latter, use current_shell(): it arbitrates all matches down to a single primary shell, preferring active version variables, then running ancestor processes, then the configured login shell. current_traits() applies no such arbitration, so it may contain several shells.

For example, on a Mac where the terminal is configured to launch fish while SHELL still points at the stock zsh:

>>> from extra_platforms import current_shell, is_fish, is_zsh
>>> is_zsh()  # The configured login shell, from SHELL.
True
>>> is_fish()  # The shell actually running, from the process tree.
True
>>> current_shell()
Shell(id='fish', name='Fish')

Recognized shells

Icon

Symbol

Name

Detection function

🪶

ASH

Almquist Shell

is_ash()

BASH

Bash

is_bash()

CMD

Command Prompt

is_cmd()

𝐂

CSH

C shell

is_csh()

💨

DASH

Dash

is_dash()

🐟

FISH

Fish

is_fish()

𝐊

KSH

Korn shell

is_ksh()

𝜈

NUSHELL

Nushell

is_nushell()

🔷

POWERSHELL

PowerShell

is_powershell()

𝐒

SH

Bourne Shell

is_sh()

𝐓

TCSH

tcsh

is_tcsh()

🐍

XONSH

Xonsh

is_xonsh()

ZSH

Zsh

is_zsh()

Hint

The UNKNOWN_SHELL trait represents an unrecognized shell. It is not included in the ALL_SHELLS group, and will be returned by current_shell() if the current shell is not recognized.

Groups of shells

Icon

Symbol

Description

Detection

Canonical

🐚

ALL_SHELLS

All shells

is_any_shell()

💲

BOURNE_SHELLS

Bourne-compatible shells

is_bourne_shells()

🅲

C_SHELLS

C shells

is_c_shells()

OTHER_SHELLS

Other shells

is_other_shells()

⌨️

WINDOWS_SHELLS

Windows shells

is_windows_shells()

Hint

Canonical groups are non-overlapping groups that together cover all recognized traits. They are marked with a ⬥ icon in the table above.

Other groups are provided for convenience, but overlap with each other or with canonical groups.

        ---
config:
  sankey:
    height: 800
    showValues: false
    width: 800

---
sankey-beta

ALL_SHELLS,BOURNE_SHELLS,6
ALL_SHELLS,OTHER_SHELLS,3
ALL_SHELLS,WINDOWS_SHELLS,2
ALL_SHELLS,C_SHELLS,2
BOURNE_SHELLS,ASH,1
BOURNE_SHELLS,BASH,1
BOURNE_SHELLS,DASH,1
BOURNE_SHELLS,KSH,1
BOURNE_SHELLS,SH,1
BOURNE_SHELLS,ZSH,1
OTHER_SHELLS,FISH,1
OTHER_SHELLS,NUSHELL,1
OTHER_SHELLS,XONSH,1
WINDOWS_SHELLS,CMD,1
WINDOWS_SHELLS,POWERSHELL,1
C_SHELLS,CSH,1
C_SHELLS,TCSH,1
    
        ---
config:
  mindmap:
    padding: 5

---
mindmap
    ((🐚 ALL_SHELLS))
        )⌨️ WINDOWS_SHELLS(
            (▶ CMD)
            (🔷 POWERSHELL)
        )◇ OTHER_SHELLS(
            (🐟 FISH)
            (𝜈 NUSHELL)
            (🐍 XONSH)
        )🅲 C_SHELLS(
            (𝐂 CSH)
            (𝐓 TCSH)
        )💲 BOURNE_SHELLS(
            (🪶 ASH)
            (# BASH)
            (💨 DASH)
            (𝐊 KSH)
            (𝐒 SH)
            (ℤ ZSH)
    

Predefined shells

Shell definitions and metadata.

extra_platforms.ASH = Shell(id='ash', name='Almquist Shell')
extra_platforms.BASH = Shell(id='bash', name='Bash')
extra_platforms.CMD = Shell(id='cmd', name='Command Prompt')
extra_platforms.CSH = Shell(id='csh', name='C shell')
extra_platforms.DASH = Shell(id='dash', name='Dash')
extra_platforms.FISH = Shell(id='fish', name='Fish')
extra_platforms.KSH = Shell(id='ksh', name='Korn shell')
extra_platforms.NUSHELL = Shell(id='nushell', name='Nushell')
extra_platforms.POWERSHELL = Shell(id='powershell', name='PowerShell')
extra_platforms.SH = Shell(id='sh', name='Bourne Shell')
extra_platforms.TCSH = Shell(id='tcsh', name='tcsh')
extra_platforms.UNKNOWN_SHELL = Shell(id='unknown_shell', name='Unknown shell')
extra_platforms.XONSH = Shell(id='xonsh', name='Xonsh')
extra_platforms.ZSH = Shell(id='zsh', name='Zsh')