Now liveThe Skillselion MCP - thousands of ranked skills, loaded into your agent mid-task. No install.Get it →
thebushidocollective avatar

Shell Portability

  • 50 installs
  • 186 repo stars
  • Updated July 19, 2026
  • thebushidocollective/han

Helps with ai & agent building tasks.

About

shell-portability is a Claude Code skill for ai & agent building. It helps solo builders move faster with AI-assisted development.

  • shell-portability
  • AI & Agent Building
  • AI-coding skill

Shell Portability by the numbers

  • 50 all-time installs (skills.sh)
  • +4 installs in the week ending Aug 5, 2026 (Skillselion tracking)
  • Ranked #7,298 of 16,546 AI & Agent Building skills by installs in the Skillselion catalog
  • Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/thebushidocollective/han --skill shell-portability

Add your badge

Show developers this skill is listed on Skillselion. Paste this into your README.

Listed on Skillselion
Installs50
repo stars186
Last updatedJuly 19, 2026
Repositorythebushidocollective/han

What it does

Helps with ai & agent building tasks.

Files

SKILL.mdMarkdownGitHub ↗

Shell Script Portability

Techniques for writing shell scripts that work across different platforms and environments.

Shebang Selection

Bash Scripts

#!/usr/bin/env bash
# Most portable for bash scripts
# Works on Linux, macOS, BSD

POSIX Shell Scripts

#!/bin/sh
# For maximum portability
# Use only POSIX features

Bash vs POSIX Differences

Arrays (Bash only)

# Bash - arrays available
declare -a items=("one" "two" "three")
for item in "${items[@]}"; do
    echo "$item"
done

# POSIX - use positional parameters or space-separated strings
set -- one two three
for item in "$@"; do
    echo "$item"
done

Test Syntax

# Bash - extended test
if [[ "$var" == "value" ]]; then
    echo "match"
fi

# POSIX - basic test
if [ "$var" = "value" ]; then
    echo "match"
fi

String Operations

# Bash - regex matching
if [[ "$input" =~ ^[0-9]+$ ]]; then
    echo "numeric"
fi

# POSIX - use case or external tools
case "$input" in
    *[!0-9]*|'') echo "not numeric" ;;
    *) echo "numeric" ;;
esac

Arithmetic

# Bash - arithmetic expansion
(( count++ ))
if (( count > 10 )); then
    echo "greater"
fi

# POSIX - expr or arithmetic expansion
count=$((count + 1))
if [ "$count" -gt 10 ]; then
    echo "greater"
fi

Platform Differences

macOS vs Linux

# Date command differences
# GNU (Linux)
date -d "yesterday" +%Y-%m-%d

# BSD (macOS)
date -v-1d +%Y-%m-%d

# Portable approach
if date --version >/dev/null 2>&1; then
    # GNU date
    yesterday=$(date -d "yesterday" +%Y-%m-%d)
else
    # BSD date
    yesterday=$(date -v-1d +%Y-%m-%d)
fi

sed Differences

# GNU sed - in-place edit
sed -i 's/old/new/g' file.txt

# BSD sed - requires backup extension
sed -i '' 's/old/new/g' file.txt

# Portable approach
sed 's/old/new/g' file.txt > file.txt.tmp && mv file.txt.tmp file.txt

# Or use a function
sed_inplace() {
    if sed --version >/dev/null 2>&1; then
        sed -i "$@"
    else
        sed -i '' "$@"
    fi
}

readlink Differences

# GNU readlink
readlink -f /path/to/link

# BSD/macOS - no -f option by default
# Use greadlink from coreutils or:
resolve_path() {
    local path="$1"
    if command -v greadlink >/dev/null 2>&1; then
        greadlink -f "$path"
    elif command -v realpath >/dev/null 2>&1; then
        realpath "$path"
    else
        # Fallback
        cd "$(dirname "$path")" && pwd -P
    fi
}

Detecting Environment

Operating System

detect_os() {
    case "$(uname -s)" in
        Linux*)  echo "linux" ;;
        Darwin*) echo "macos" ;;
        MINGW*|CYGWIN*|MSYS*) echo "windows" ;;
        FreeBSD*) echo "freebsd" ;;
        *) echo "unknown" ;;
    esac
}

OS=$(detect_os)
case "$OS" in
    linux)  INSTALL_CMD="apt-get install" ;;
    macos)  INSTALL_CMD="brew install" ;;
esac

Architecture

detect_arch() {
    case "$(uname -m)" in
        x86_64|amd64) echo "amd64" ;;
        aarch64|arm64) echo "arm64" ;;
        armv7l) echo "arm" ;;
        *) echo "unknown" ;;
    esac
}

Shell Detection

detect_shell() {
    if [ -n "$BASH_VERSION" ]; then
        echo "bash"
    elif [ -n "$ZSH_VERSION" ]; then
        echo "zsh"
    else
        echo "sh"
    fi
}

Portable Patterns

Reading Files

# Portable line reading
while IFS= read -r line || [ -n "$line" ]; do
    echo "$line"
done < "$file"
# The || [ -n "$line" ] handles files without trailing newline

Temporary Files

# POSIX-compatible temp file
make_temp() {
    if command -v mktemp >/dev/null 2>&1; then
        mktemp
    else
        # Fallback
        local tmp="/tmp/tmp.$$.$RANDOM"
        touch "$tmp" && echo "$tmp"
    fi
}

Command Existence Check

# POSIX-compatible command check
has_command() {
    command -v "$1" >/dev/null 2>&1
}

# Usage
if has_command curl; then
    curl "$url"
elif has_command wget; then
    wget -O- "$url"
else
    echo "No HTTP client available" >&2
    exit 1
fi

String Contains

# POSIX-compatible string contains
contains() {
    case "$1" in
        *"$2"*) return 0 ;;
        *) return 1 ;;
    esac
}

# Usage
if contains "$PATH" "/usr/local/bin"; then
    echo "Found in PATH"
fi

ShellCheck Compatibility

Disabling Warnings for Portability

# When intentionally using non-portable features
# shellcheck disable=SC2039  # Bash-specific feature
if [[ "$var" =~ regex ]]; then
    :
fi

# Document why
# shellcheck disable=SC2016  # Intentionally not expanding
echo 'Use $HOME for home directory'

Testing Multiple Shells

#!/usr/bin/env bash
# shellcheck shell=bash

# Or for POSIX:
#!/bin/sh
# shellcheck shell=sh

Best Practices

1. Choose the right shebang for your needs 2. Document shell requirements in README 3. Use #!/usr/bin/env bash for bash scripts 4. Test on multiple platforms when possible 5. Prefer POSIX features when portability matters 6. Abstract platform differences into functions 7. Use ShellCheck with appropriate shell directive 8. Provide fallbacks for platform-specific commands

Related skills

This week in AI coding

Five minutes, every Monday - the tools, releases and tactics for developers.

unsubscribe anytime.