Open-Source Wikis

/

Ansible

/

Plugins

/

Shell plugins (and a note on strategy)

ansible/ansible

Shell plugins (and a note on strategy)

Shell plugins handle the platform-specific logic for quoting commands, joining environment variables, and choosing how to wrap shell invocations on a remote target. Strategy plugins (covered in their own dedicated Strategy page) decide when to dispatch tasks; shell plugins decide how to format the commands the connection plugin then sends.

Shell plugins

ansible-core ships shell plugins for each major remote shell:

lib/ansible/plugins/shell/
├── __init__.py    # ShellBase
├── sh.py          # POSIX sh — the common case
├── cmd.py         # Windows cmd.exe
├── powershell.py  # Windows PowerShell
├── csh.py
└── fish.py

The shell plugin is selected based on the target's ansible_shell_type (set automatically based on connection plugin and gathered facts). Action plugins use it to:

  • Build environment-prefixed commands: ENV_VAR=value /bin/sh -c 'cmd'.
  • Quote arguments correctly for the shell.
  • Generate temp directory creation/removal commands.
  • Build the AnsiBallZ wrapper invocation.
  • Format chmod/chown calls.

ShellBase contract

Attribute / method Purpose
COMPATIBLE_SHELLS Set of shell types this plugin handles
SHELL_FAMILY sh, csh, powershell, cmd
quote(arg) Shell-quote a single argument
join_path(*args) Join paths with the shell's separator
mkdtemp(...) Build a mktemp -d command
expand_user(path) Build a ~user expansion command
set_user_facl(path, user, mode) ACL helper
chmod(paths, mode), chown(paths, user, group)
env_prefix(env_dict) KEY=val ANOTHER=val ...
pwd() Print working directory command
command_sep ; for sh, \n for PowerShell

sh

lib/ansible/plugins/shell/sh.py is the workhorse. POSIX-compliant quoting (single-quotes with embedded '\'' escapes), mktemp -d, chmod $mode $path, etc.

powershell

lib/ansible/plugins/shell/powershell.py is the Windows equivalent and significantly more involved than sh.py. It handles:

  • PowerShell-specific quoting ('value' vs "value" rules).
  • New-Item -ItemType Directory for mkdir.
  • Get-ItemProperty for stat-equivalent operations.
  • The full PowerShell wrapper boilerplate that lib/ansible/executor/powershell/ references.

PowerShell is unique because the AnsiBallZ-equivalent flow is different: instead of a Python script, it's a PowerShell script with embedded C# helper assemblies (compiled by PowerShell at runtime). The shell plugin is part of the wrapper-construction pipeline.

cmd

lib/ansible/plugins/shell/cmd.py is for cmd.exe. Mostly a fallback for older Windows targets that don't have PowerShell available; modern Windows automation uses the powershell shell.

csh, fish

Niche but supported. Useful for the rare target running a non-POSIX login shell where the executor needs to syntax-match.

Why shell plugins matter

Without a correct shell plugin:

  • Quoting bugs → injection vulnerabilities.
  • Environment variables don't propagate.
  • mkdir/chmod/rm commands fail in subtle ways.
  • AnsiBallZ wrappers don't execute correctly.

The bulk of platform-specific quirks for "running a command on a remote target" live here. When porting Ansible to a new shell or shell-flavor, the shell plugin is the bulk of the work.

A note on strategy

The strategy plugin and the shell plugin are independent — one decides which task to run next, the other decides how to format the command for that task. They don't interact directly. The strategy hands a task to a worker; the worker's TaskExecutor instantiates an action plugin; the action plugin calls into the connection plugin; the connection plugin uses the shell plugin to build the actual remote command line.

For the deep dive on strategies — linear, free, host_pinned, debug — see Strategy.

Integration points

  • Imported by: action plugins (when building exec commands), connection plugins (when wrapping exec_command), lib/ansible/executor/module_common.py (when building AnsiBallZ wrapper invocations).
  • Selected by: ansible_shell_type per host. Set automatically; can be overridden in inventory.
  • Loaded by: shell_loader in lib/ansible/plugins/loader.py.

Entry points for modification

  • Quoting bug for an unusual shell — fix in the relevant lib/ansible/plugins/shell/*.py file.
  • A new shell — write a plugin in a collection. Subclass ShellBase. Set COMPATIBLE_SHELLS and SHELL_FAMILY. Implement quoting and the path/file-handling commands.

Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.

Shell plugins (and a note on strategy) – Ansible wiki | Factory