
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-portabilityAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 50 |
|---|---|
| repo stars | ★ 186 |
| Last updated | July 19, 2026 |
| Repository | thebushidocollective/han ↗ |
What it does
Helps with ai & agent building tasks.
Files
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, BSDPOSIX Shell Scripts
#!/bin/sh
# For maximum portability
# Use only POSIX featuresBash 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"
doneTest Syntax
# Bash - extended test
if [[ "$var" == "value" ]]; then
echo "match"
fi
# POSIX - basic test
if [ "$var" = "value" ]; then
echo "match"
fiString 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" ;;
esacArithmetic
# 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"
fiPlatform 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)
fised 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" ;;
esacArchitecture
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 newlineTemporary 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
fiString 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"
fiShellCheck 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=shBest 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