POSIX Shell Pro 脚本编写指南:跨平台兼容、可移植性与最佳实践 | SkillsMDPOSIX Shell Pro 脚本编写指南:跨平台兼容、可移植性与最佳实践
posix-shell-pro by sickn33/antigravity-awesome-skills
npx skills add https://github.com/sickn33/antigravity-awesome-skills --skill posix-shell-pro🇨🇳中文介绍
使用此技能的场景
- 处理 posix shell pro 任务或工作流时
- 需要 posix shell pro 的指导、最佳实践或检查清单时
不应使用此技能的场景
- 任务与 posix shell pro 无关时
- 需要此范围之外的不同领域或工具时
使用说明
- 明确目标、约束条件和所需输入。
- 应用相关的最佳实践并验证结果。
- 提供可操作的步骤和验证方法。
- 如果需要详细示例,请打开
resources/implementation-playbook.md。
重点领域
- 严格遵守 POSIX 标准以实现最大可移植性
- 编写与具体 Shell 无关、可在任何类 Unix 系统上运行的脚本
- 采用防御性编程,包含可移植的错误处理
- 使用不依赖 bash 特定功能的安全参数解析
- 可移植的文件操作和资源管理
- 跨平台兼容性(Linux、BSD、Solaris、AIX、macOS)
- 使用 dash、ash 和 POSIX 模式验证进行测试
- 在 POSIX 模式下使用 ShellCheck 进行静态分析
- 采用极简主义方法,仅使用 POSIX 规定的功能
- 兼容遗留系统和嵌入式环境
POSIX 约束
- 无数组(使用位置参数或分隔字符串)
- 无
[[ 条件判断(仅使用 [ 测试命令)
- 无进程替换 或
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
联系我们<()
>()
无花括号扩展 {1..10}无 local 关键字(谨慎使用函数作用域变量)无 declare、typeset 或 readonly 用于变量属性无 += 操作符用于字符串连接无 ${var//pattern/replacement} 替换无关联数组或哈希表无 source 命令(使用 . 来引入文件)方法
- 始终使用
#!/bin/sh 作为 POSIX shell 的 shebang
- 使用
set -eu 进行错误处理(POSIX 中无 pipefail)
- 引用所有变量扩展:
"$var" 而不是 $var
- 使用
[ ] 进行所有条件测试,绝不使用 [[
- 使用
while 和 case 实现参数解析(长选项不使用 getopts)
- 使用
mktemp 安全创建临时文件并设置清理陷阱
- 所有输出使用
printf 而非 echo(echo 行为多变)
- 使用
. script.sh 而非 source script.sh 来引入文件
- 通过显式的
|| exit 1 检查实现错误处理
- 设计脚本使其具有幂等性并支持试运行模式
- 谨慎操作
IFS 并恢复其原始值
- 使用
[ -n "$var" ] 和 [ -z "$var" ] 测试验证输入
- 使用
-- 结束选项解析,并使用 rm -rf -- "$dir" 以确保安全
- 使用命令替换
$() 而非反引号以提高可读性
- 使用
date 实现带时间戳的结构化日志记录
- 使用 dash/ash 测试脚本以验证 POSIX 合规性
兼容性与可移植性
- 使用
#!/bin/sh 调用系统的 POSIX shell
- 在多个 shell 上测试:dash(Debian/Ubuntu 默认)、ash(Alpine/BusyBox)、bash --posix
- 避免 GNU 特定选项;仅使用 POSIX 规定的标志
- 处理平台差异:使用
uname -s 进行操作系统检测
- 使用
command -v 而非 which(更具可移植性)
- 检查命令可用性:
command -v cmd >/dev/null 2>&1 || exit 1
- 为缺失的工具提供可移植的实现
- 使用
[ -e "$file" ] 进行存在性检查(在所有系统上有效)
- 避免使用
/dev/stdin、/dev/stdout(并非普遍可用)
- 使用显式重定向而非
&>(bash 特定)
可读性与可维护性
- 使用描述性变量名:导出变量用 UPPER_CASE,局部变量用 lower_case
- 添加带注释块的章节标题以组织代码
- 保持函数在 50 行以内;提取复杂逻辑
- 使用一致的缩进(仅使用空格,通常为 2 或 4 个)
- 在注释中记录函数目的和参数
- 使用有意义的名称:例如
validate_input 而非 check
- 为非显而易见的 POSIX 变通方法添加注释
- 使用描述性标题对相关函数进行分组
- 将重复代码提取到函数中
- 使用空行分隔逻辑部分
安全与安全模式
- 引用所有变量扩展以防止单词分割
- 操作前验证文件权限:
[ -r "$file" ] || exit 1
- 在命令中使用用户输入前进行清理
- 验证数字输入:
case $num in *[!0-9]*) exit 1 ;; esac
- 切勿对不受信任的输入使用
eval
- 使用
-- 分隔选项和参数:rm -- "$file"
- 验证必需变量:
[ -n "$VAR" ] || { echo "VAR required" >&2; exit 1; }
- 显式检查退出码:
cmd || { echo "failed" >&2; exit 1; }
- 使用
trap 进行清理:trap 'rm -f "$tmpfile"' EXIT INT TERM
- 为敏感文件设置限制性 umask:
umask 077
- 将安全相关操作记录到系统日志或文件
- 验证文件路径不包含意外字符
- 在安全关键脚本中使用命令的完整路径:
/bin/rm 而非 rm
性能优化
- 尽可能使用 shell 内置命令而非外部命令
- 避免在循环中生成子 shell:使用
while read 而非 for i in $(cat)
- 将命令结果缓存在变量中而非重复执行
- 使用
case 进行多个字符串比较(比重复的 if 更快)
- 对大文件进行逐行处理
- 使用
expr 或 $(( )) 进行算术运算(POSIX 支持 $(( )))
- 在紧密循环中最小化外部命令调用
- 仅需真/假判断时使用
grep -q(比捕获输出更快)
- 将类似操作批量处理
- 使用 here-documents 处理多行字符串而非多次调用 echo
文档标准
- 实现
-h 标志以提供帮助(若无适当解析则避免使用 --help)
- 包含显示语法和选项的用法信息
- 清晰记录必需参数与可选参数
- 列出退出码:0=成功,1=错误,特定代码对应特定失败
- 记录先决条件和必需命令
- 添加包含脚本目的和作者的头部注释
- 包含常见使用模式的示例
- 记录脚本使用的环境变量
- 为常见问题提供故障排除指南
- 在文档中注明 POSIX 合规性
无数组情况下的工作方式
由于 POSIX sh 缺少数组,请使用以下模式:
- 位置参数 :
set -- item1 item2 item3; for arg; do echo "$arg"; done
- 分隔字符串 :
items="a:b:c"; IFS=:; set -- $items; IFS=' '
- 换行分隔 :
items="a\nb\nc"; while IFS= read -r item; do echo "$item"; done <<EOF
- 计数器 :
i=0; while [ $i -lt 10 ]; do i=$((i+1)); done
- 字段分割 : 使用
cut、awk 或参数扩展进行字符串分割
可移植的条件判断
- 文件测试 :
[ -e file ] 存在,[ -f file ] 常规文件,[ -d dir ] 目录
- 字符串测试 :
[ -z "$str" ] 为空,[ -n "$str" ] 非空,[ "$a" = "$b" ] 相等
- 数值测试 :
[ "$a" -eq "$b" ] 相等,[ "$a" -lt "$b" ] 小于
- 逻辑运算 :
[ cond1 ] && [ cond2 ] 与,[ cond1 ] || [ cond2 ] 或
- 取反 :
[ ! -f file ] 不是文件
- 模式匹配 : 使用
case 而非 [[ =~ ]]
CI/CD 集成
- 矩阵测试 : 在 Linux、macOS、Alpine 上跨 dash、ash、bash --posix、yash 进行测试
- 容器测试 : 使用 alpine:latest(ash)、debian:stable(dash)进行可重复测试
- 预提交钩子 : 配置 checkbashisms、shellcheck -s sh、shfmt -ln posix
- GitHub Actions : 在 POSIX 模式下使用 shellcheck-problem-matchers
- 跨平台验证 : 在 Linux、macOS、FreeBSD、NetBSD 上测试
- BusyBox 测试 : 在嵌入式系统的 BusyBox 环境中验证
- 自动化发布 : 标记版本并生成可移植的分发包
- 覆盖率跟踪 : 确保所有 POSIX shell 的测试覆盖率
- 示例工作流:
shellcheck -s sh *.sh && shfmt -ln posix -d *.sh && checkbashisms *.sh
嵌入式系统与受限环境
- BusyBox 兼容性 : 使用 BusyBox 有限的 ash 实现进行测试
- Alpine Linux : 默认 shell 是 BusyBox ash,而非 bash
- 资源限制 : 最小化内存使用,避免生成过多进程
- 缺失工具 : 当常用工具不可用时提供回退方案(
mktemp、seq)
- 只读文件系统 : 处理
/tmp 可能受限的情况
- 无 coreutils : 某些环境缺少 GNU coreutils 扩展
- 信号处理 : 最小化环境中的信号支持有限
- 启动脚本 : 为获得最大兼容性,初始化脚本必须是 POSIX 的
- 示例:检查 mktemp:
command -v mktemp >/dev/null 2>&1 || mktemp() { ... }
从 Bash 迁移到 POSIX sh
- 评估 : 运行
checkbashisms 以识别 bash 特定的结构
- 数组消除 : 将数组转换为分隔字符串或位置参数
- 条件判断更新 : 将
[[ 替换为 [ 并将正则表达式调整为 case 模式
- 局部变量 : 移除
local 关键字,改用函数前缀
- 进程替换 : 将
<() 替换为临时文件或管道
- 参数扩展 : 使用
sed/awk 进行复杂的字符串操作
- 测试策略 : 通过持续验证进行增量转换
- 文档 : 记录任何 POSIX 限制或变通方法
- 逐步迁移 : 一次转换一个函数,彻底测试
- 回退支持 : 如果需要,在过渡期间维护双重实现
质量检查清单
- 脚本通过带有
-s sh 标志的 ShellCheck(POSIX 模式)
- 代码使用 shfmt 的
-ln posix 选项进行一致格式化
- 在多个 shell 上测试:dash、ash、bash --posix、yash
- 所有变量扩展都已正确引用
- 未使用 bash 特定功能(数组、
[[、local 等)
- 错误处理覆盖所有失败模式
- 使用 EXIT 陷阱清理临时资源
- 脚本提供清晰的用法信息
- 输入验证可防止注入攻击
- 脚本在类 Unix 系统间可移植(Linux、BSD、Solaris、macOS、Alpine)
- 已针对嵌入式用例验证 BusyBox 兼容性
- 未使用 GNU 特定扩展或标志
输出
- 符合 POSIX 标准、最大化可移植性的 shell 脚本
- 使用 shellspec 或 bats-core 在 dash、ash、yash 上进行验证的测试套件
- 用于多 shell 矩阵测试的 CI/CD 配置
- 具有回退方案的常见模式的可移植实现
- 关于 POSIX 限制和变通方法的文档及示例
- 用于将 bash 脚本逐步转换为 POSIX sh 的迁移指南
- 跨平台兼容性矩阵(Linux、BSD、macOS、Solaris、Alpine)
- 比较不同 POSIX shell 的性能基准
- 针对缺失工具的回退实现(mktemp、seq、timeout)
- 适用于嵌入式和容器环境的 BusyBox 兼容脚本
- 针对各种平台的无 bash 依赖的软件包分发
必备工具
静态分析与格式化
- ShellCheck : 静态分析器,带有用于 POSIX 模式验证的
-s sh 选项
- shfmt : Shell 格式化工具,带有用于 POSIX 语法的
-ln posix 选项
- checkbashisms : 检测脚本中的 bash 特定结构(来自 devscripts)
- Semgrep : 带有 POSIX 特定安全规则的 SAST
- CodeQL : 用于 shell 脚本的安全扫描
用于测试的 POSIX Shell 实现
- dash : Debian Almquist Shell - 轻量级,严格遵守 POSIX 标准(主要测试目标)
- ash : Almquist Shell - BusyBox 默认,嵌入式系统
- yash : Yet Another Shell - 严格的 POSIX 一致性验证
- posh : Policy-compliant Ordinary Shell - Debian 策略合规性
- osh : Oil Shell - 具有更好错误消息的现代 POSIX 兼容 shell
- bash --posix : 用于兼容性测试的 POSIX 模式下的 GNU Bash
测试框架
- bats-core : Bash 测试框架(适用于 POSIX sh)
- shellspec : 支持 POSIX sh 的 BDD 风格测试
- shunit2 : 支持 POSIX sh 的 xUnit 风格框架
- sharness : Git 使用的测试框架(POSIX 兼容)
应避免的常见陷阱
- 使用
[[ 而非 [(bash 特定)
- 使用数组(POSIX sh 中不存在)
- 使用
local 关键字(bash/ksh 扩展)
- 不使用
printf 而使用 echo(行为因实现而异)
- 使用
source 而非 . 来引入脚本
- 使用 bash 特定的参数扩展:
${var//pattern/replacement}
- 使用进程替换
<() 或 >()
- 使用
function 关键字(ksh/bash 语法)
- 使用
$RANDOM 变量(POSIX 中不存在)
- 使用
read -a 处理数组(bash 特定)
- 使用
set -o pipefail(bash 特定)
- 使用
&> 进行重定向(使用 >file 2>&1)
高级技巧
- 错误捕获 :
trap 'echo "Error at line $LINENO" >&2; exit 1' EXIT; trap - EXIT 成功时
- 安全临时文件 :
tmpfile=$(mktemp) || exit 1; trap 'rm -f "$tmpfile"' EXIT INT TERM
- 模拟数组 :
set -- item1 item2 item3; for arg; do process "$arg"; done
- 字段解析 :
IFS=:; while read -r user pass uid gid; do ...; done < /etc/passwd
- 字符串替换 :
echo "$str" | sed 's/old/new/g' 或使用参数扩展 ${str%suffix}
- 默认值 :
value=${var:-default} 如果 var 未设置或为空则分配默认值
- 可移植函数 : 避免
function 关键字,使用 func_name() { ... }
- 子 shell 隔离 :
(cd dir && cmd) 更改目录而不影响父进程
- Here-documents : 带引号的
cat <<'EOF' 可防止变量扩展
- 命令存在性 :
command -v cmd >/dev/null 2>&1 && echo "found" || echo "missing"
POSIX 特定最佳实践
- 始终引用变量扩展:
"$var" 而非 $var
- 使用带适当空格的
[ ]:[ "$a" = "$b" ] 而非 ["$a"="$b"]
- 使用
= 进行字符串比较,而非 ==(bash 扩展)
- 使用
. 进行引入,而非 source
- 所有输出使用
printf,避免使用 echo -e 或 echo -n
- 使用
$(( )) 进行算术运算,而非 let 或 declare -i
- 使用
case 进行模式匹配,而非 [[ =~ ]]
- 使用
sh -n script.sh 测试脚本以检查语法
- 使用
command -v 而非 type 或 which 以提高可移植性
- 使用
|| exit 1 显式处理所有错误条件
参考资料与延伸阅读
POSIX 标准与规范
可移植性与最佳实践
工具与测试
🇺🇸English
Use this skill when
- Working on posix shell pro tasks or workflows
- Needing guidance, best practices, or checklists for posix shell pro
Do not use this skill when
- The task is unrelated to posix shell pro
- You need a different domain or tool outside this scope
Instructions
- Clarify goals, constraints, and required inputs.
- Apply relevant best practices and validate outcomes.
- Provide actionable steps and verification.
- If detailed examples are required, open
resources/implementation-playbook.md.
Focus Areas
- Strict POSIX compliance for maximum portability
- Shell-agnostic scripting that works on any Unix-like system
- Defensive programming with portable error handling
- Safe argument parsing without bash-specific features
- Portable file operations and resource management
- Cross-platform compatibility (Linux, BSD, Solaris, AIX, macOS)
- Testing with dash, ash, and POSIX mode validation
- Static analysis with ShellCheck in POSIX mode
- Minimalist approach using only POSIX-specified features
- Compatibility with legacy systems and embedded environments
POSIX Constraints
- No arrays (use positional parameters or delimited strings)
- No
[[ conditionals (use [ test command only)
- No process substitution
<() or >()
- No brace expansion
{1..10}
- No
local keyword (use function-scoped variables carefully)
- No
declare, typeset, or readonly for variable attributes
- No
+= operator for string concatenation
- No
${var//pattern/replacement} substitution
- No associative arrays or hash tables
- No
source command (use . for sourcing files)
Approach
- Always use
#!/bin/sh shebang for POSIX shell
- Use
set -eu for error handling (no pipefail in POSIX)
- Quote all variable expansions:
"$var" never $var
- Use
[ ] for all conditional tests, never [[
- Implement argument parsing with
while and case (no getopts for long options)
- Create temporary files safely with
mktemp and cleanup traps
Compatibility & Portability
- Use
#!/bin/sh to invoke the system's POSIX shell
- Test on multiple shells: dash (Debian/Ubuntu default), ash (Alpine/BusyBox), bash --posix
- Avoid GNU-specific options; use POSIX-specified flags only
- Handle platform differences:
uname -s for OS detection
- Use
command -v instead of which (more portable)
- Check for command availability:
command -v cmd >/dev/null 2>&1 || exit 1
- Provide portable implementations for missing utilities
- Use
[ -e "$file" ] for existence checks (works on all systems)
- Avoid
/dev/stdin, /dev/stdout (not universally available)
- Use explicit redirection instead of
&> (bash-specific)
Readability & Maintainability
- Use descriptive variable names in UPPER_CASE for exports, lower_case for locals
- Add section headers with comment blocks for organization
- Keep functions under 50 lines; extract complex logic
- Use consistent indentation (spaces only, typically 2 or 4)
- Document function purpose and parameters in comments
- Use meaningful names:
validate_input not check
- Add comments for non-obvious POSIX workarounds
- Group related functions with descriptive headers
- Extract repeated code into functions
- Use blank lines to separate logical sections
Safety & Security Patterns
- Quote all variable expansions to prevent word splitting
- Validate file permissions before operations:
[ -r "$file" ] || exit 1
- Sanitize user input before using in commands
- Validate numeric input:
case $num in *[!0-9]*) exit 1 ;; esac
- Never use
eval on untrusted input
- Use
-- to separate options from arguments: rm -- "$file"
- Validate required variables:
[ -n "$VAR" ] || { echo "VAR required" >&2; exit 1; }
- Check exit codes explicitly:
cmd || { echo "failed" >&2; exit 1; }
- Use
trap for cleanup: trap 'rm -f "$tmpfile"' EXIT INT TERM
Performance Optimization
- Use shell built-ins over external commands when possible
- Avoid spawning subshells in loops: use
while read not for i in $(cat)
- Cache command results in variables instead of repeated execution
- Use
case for multiple string comparisons (faster than repeated if)
- Process files line-by-line for large files
- Use
expr or $(( )) for arithmetic (POSIX supports $(( )))
- Minimize external command calls in tight loops
- Use
grep -q when you only need true/false (faster than capturing output)
- Batch similar operations together
- Use here-documents for multi-line strings instead of multiple echo calls
Documentation Standards
- Implement
-h flag for help (avoid --help without proper parsing)
- Include usage message showing synopsis and options
- Document required vs optional arguments clearly
- List exit codes: 0=success, 1=error, specific codes for specific failures
- Document prerequisites and required commands
- Add header comment with script purpose and author
- Include examples of common usage patterns
- Document environment variables used by script
- Provide troubleshooting guidance for common issues
- Note POSIX compliance in documentation
Working Without Arrays
Since POSIX sh lacks arrays, use these patterns:
- Positional Parameters :
set -- item1 item2 item3; for arg; do echo "$arg"; done
- Delimited Strings :
items="a:b:c"; IFS=:; set -- $items; IFS=' '
- Newline-Separated :
items="a\nb\nc"; while IFS= read -r item; do echo "$item"; done <<EOF
- Counters :
i=0; while [ $i -lt 10 ]; do i=$((i+1)); done
- Field Splitting : Use
cut, awk, or parameter expansion for string splitting
Portable Conditionals
Use [ ] test command with POSIX operators:
- File Tests :
[ -e file ] exists, [ -f file ] regular file, [ -d dir ] directory
- String Tests :
[ -z "$str" ] empty, [ -n "$str" ] not empty, [ "$a" = "$b" ] equal
- Numeric Tests :
[ "$a" -eq "$b" ] equal, [ "$a" -lt "$b" ] less than
- Logical :
[ cond1 ] && [ cond2 ] AND, [ cond1 ] || [ cond2 ] OR
CI/CD Integration
- Matrix testing : Test across dash, ash, bash --posix, yash on Linux, macOS, Alpine
- Container testing : Use alpine:latest (ash), debian:stable (dash) for reproducible tests
- Pre-commit hooks : Configure checkbashisms, shellcheck -s sh, shfmt -ln posix
- GitHub Actions : Use shellcheck-problem-matchers with POSIX mode
- Cross-platform validation : Test on Linux, macOS, FreeBSD, NetBSD
- BusyBox testing : Validate on BusyBox environments for embedded systems
- Automated releases : Tag versions and generate portable distribution packages
- Coverage tracking : Ensure test coverage across all POSIX shells
- Example workflow:
shellcheck -s sh *.sh && shfmt -ln posix -d *.sh && checkbashisms *.sh
Embedded Systems & Limited Environments
- BusyBox compatibility : Test with BusyBox's limited ash implementation
- Alpine Linux : Default shell is BusyBox ash, not bash
- Resource constraints : Minimize memory usage, avoid spawning excessive processes
- Missing utilities : Provide fallbacks when common tools unavailable (
mktemp, seq)
- Read-only filesystems : Handle scenarios where
/tmp may be restricted
- No coreutils : Some environments lack GNU coreutils extensions
- Signal handling : Limited signal support in minimal environments
- Startup scripts : Init scripts must be POSIX for maximum compatibility
- Example: Check for mktemp:
command -v mktemp >/dev/null 2>&1 || mktemp() { ... }
Migration from Bash to POSIX sh
- Assessment : Run
checkbashisms to identify bash-specific constructs
- Array elimination : Convert arrays to delimited strings or positional parameters
- Conditional updates : Replace
[[ with [ and adjust regex to case patterns
- Local variables : Remove
local keyword, use function prefixes instead
- Process substitution : Replace
<() with temporary files or pipes
- Parameter expansion : Use
sed/awk for complex string manipulation
- Testing strategy : Incremental conversion with continuous validation
Quality Checklist
- Scripts pass ShellCheck with
-s sh flag (POSIX mode)
- Code is formatted consistently with shfmt using
-ln posix
- Test on multiple shells: dash, ash, bash --posix, yash
- All variable expansions are properly quoted
- No bash-specific features used (arrays,
[[, local, etc.)
- Error handling covers all failure modes
- Temporary resources cleaned up with EXIT trap
- Scripts provide clear usage information
- Input validation prevents injection attacks
- Scripts portable across Unix-like systems (Linux, BSD, Solaris, macOS, Alpine)
- BusyBox compatibility validated for embedded use cases
- No GNU-specific extensions or flags used
Output
- POSIX-compliant shell scripts maximizing portability
- Test suites using shellspec or bats-core validating across dash, ash, yash
- CI/CD configurations for multi-shell matrix testing
- Portable implementations of common patterns with fallbacks
- Documentation on POSIX limitations and workarounds with examples
- Migration guides for converting bash scripts to POSIX sh incrementally
- Cross-platform compatibility matrices (Linux, BSD, macOS, Solaris, Alpine)
- Performance benchmarks comparing different POSIX shells
- Fallback implementations for missing utilities (mktemp, seq, timeout)
- BusyBox-compatible scripts for embedded and container environments
- Package distributions for various platforms without bash dependency
Essential Tools
Static Analysis & Formatting
- ShellCheck : Static analyzer with
-s sh for POSIX mode validation
- shfmt : Shell formatter with
-ln posix option for POSIX syntax
- checkbashisms : Detects bash-specific constructs in scripts (from devscripts)
- Semgrep : SAST with POSIX-specific security rules
- CodeQL : Security scanning for shell scripts
POSIX Shell Implementations for Testing
- dash : Debian Almquist Shell - lightweight, strict POSIX compliance (primary test target)
- ash : Almquist Shell - BusyBox default, embedded systems
- yash : Yet Another Shell - strict POSIX conformance validation
- posh : Policy-compliant Ordinary Shell - Debian policy compliance
- osh : Oil Shell - modern POSIX-compatible shell with better error messages
- bash --posix : GNU Bash in POSIX mode for compatibility testing
Testing Frameworks
- bats-core : Bash testing framework (works with POSIX sh)
- shellspec : BDD-style testing that supports POSIX sh
- shunit2 : xUnit-style framework with POSIX sh support
- sharness : Test framework used by Git (POSIX-compatible)
Common Pitfalls to Avoid
- Using
[[ instead of [ (bash-specific)
- Using arrays (not in POSIX sh)
- Using
local keyword (bash/ksh extension)
- Using
echo without printf (behavior varies across implementations)
- Using
source instead of . for sourcing scripts
- Using bash-specific parameter expansion:
${var//pattern/replacement}
- Using process substitution
<() or >()
Advanced Techniques
- Error Trapping :
trap 'echo "Error at line $LINENO" >&2; exit 1' EXIT; trap - EXIT on success
- Safe Temp Files :
tmpfile=$(mktemp) || exit 1; trap 'rm -f "$tmpfile"' EXIT INT TERM
- Simulating Arrays :
set -- item1 item2 item3; for arg; do process "$arg"; done
- Field Parsing :
IFS=:; while read -r user pass uid gid; do ...; done < /etc/passwd
- String Replacement :
echo "$str" | sed 's/old/new/g' or use parameter expansion ${str%suffix}
- Default Values :
value=${var:-default} assigns default if var unset or null
POSIX-Specific Best Practices
- Always quote variable expansions:
"$var" not $var
- Use
[ ] with proper spacing: [ "$a" = "$b" ] not ["$a"="$b"]
- Use
= for string comparison, not == (bash extension)
- Use
. for sourcing, not source
- Use
printf for all output, avoid echo -e or
References & Further Reading
POSIX Standards & Specifications
- POSIX Shell Command Language - Official POSIX.1-2024 specification
- POSIX Utilities - Complete list of POSIX-mandated utilities
- Autoconf Portable Shell Programming - Comprehensive portability guide from GNU
Portability & Best Practices
- Rich's sh (POSIX shell) tricks - Advanced POSIX shell techniques
- Suckless Shell Style Guide - Minimalist POSIX sh patterns
- FreeBSD Porter's Handbook - Shell - BSD portability considerations
Tools & Testing
- checkbashisms - Detect bash-specific constructs
Weekly Installs
113
Repository
sickn33/antigra…e-skills
GitHub Stars
27.4K
First Seen
Jan 28, 2026
Security Audits
Gen Agent Trust HubPassSocketPassSnykPass
Installed on
opencode103
gemini-cli95
cursor91
codex90
github-copilot90
claude-code84
Skills CLI 使用指南:AI Agent 技能包管理器安装与管理教程
43,100 周安装
Use printf instead of echo for all output (echo behavior varies)Use . script.sh instead of source script.sh for sourcingImplement error handling with explicit || exit 1 checksDesign scripts to be idempotent and support dry-run modesUse IFS manipulation carefully and restore original valueValidate inputs with [ -n "$var" ] and [ -z "$var" ] testsEnd option parsing with -- and use rm -rf -- "$dir" for safetyUse command substitution $() instead of backticks for readabilityImplement structured logging with timestamps using dateTest scripts with dash/ash to verify POSIX complianceSet restrictive umask for sensitive files: umask 077Log security-relevant operations to syslog or fileValidate file paths don't contain unexpected charactersUse full paths for commands in security-critical scripts: /bin/rm not rmNegation : [ ! -f file ] not a filePattern Matching : Use case not [[ =~ ]]Documentation : Note any POSIX limitations or workaroundsGradual migration : Convert one function at a time, test thoroughlyFallback support : Maintain dual implementations during transition if neededUsing function keyword (ksh/bash syntax)Using $RANDOM variable (not in POSIX)Using read -a for arrays (bash-specific)Using set -o pipefail (bash-specific)Using &> for redirection (use >file 2>&1)Portable Functions : Avoid function keyword, use func_name() { ... }Subshell Isolation : (cd dir && cmd) changes directory without affecting parentHere-documents : cat <<'EOF' with quotes prevents variable expansionCommand Existence : command -v cmd >/dev/null 2>&1 && echo "found" || echo "missing"echo -n
Use $(( )) for arithmetic, not let or declare -iUse case for pattern matching, not [[ =~ ]]Test scripts with sh -n script.sh to check syntaxUse command -v not type or which for portabilityExplicitly handle all error conditions with || exit 1