在 macos 上编写跨平台 shell 脚本需谨慎处理路径:用 dirname "$0" 定位脚本目录,引号包裹变量路径,避免非标准工具选项,必要时用 python 的 pathlib 或 os 模块兜底。
在 macos 上写 shell 脚本时,要让它也能在 linux、wsl 甚至部分 bsd 环境中可靠运行,路径处理是第一个必须小心的环节。macos 和 linux 都用 / 作路径分隔符,看似统一,但实际差异藏在细节里:比如脚本位置定位、相对路径解析、挂载点行为、以及工具对路径的容错性(如 sed 或 find 在不同系统上对含空格或特殊字符路径的处理)。
用 dirname "$0" 定位脚本根目录
硬编码路径(如 /Users/me/project/data)必然失败。正确做法是让脚本自己“找到家”:
- 始终用
dirname "$0"获取脚本所在目录,再拼接子路径 - 用
cd "$(dirname "$0")"切换到脚本目录,后续操作基于当前工作目录进行 - 避免直接用
~或$HOME拼路径,因为执行环境可能未加载用户 shell 配置(如 cron 或 systemd 启动时)
路径拼接时加引号并避免裸露通配符
macOS 的默认 shell 是 zsh,而很多跨平台场景(如 Alpine、CI 环境)用的是 dash 或 busybox sh,它们对未引号包裹的路径更敏感:
macOS 微信消息自动化工具。通过 GUI 自动化实现:发送消息给指定联系人、读取聊天内容、监控新消息。适用于需要自动化微信操作的场景,如定时发送、批量回复、消息备份等。依赖 peekaboo 进行屏幕截图和 UI 交互。仅支持 macOS。开源地址:https://github.com/chairmanmia...
- 所有含变量或通配符的路径必须用双引号包裹:
"$SCRIPT_DIR/config.yaml",而不是$SCRIPT_DIR/config.yaml - 遍历文件时,
for file in *.log在空目录下会字面返回*.log字符串——应改用for file in "$SCRIPT_DIR"/*.log; do [ -e "$file" ] || continue; ... - 用
find替代 glob 更稳妥:find "$SCRIPT_DIR" -maxdepth 1 -name "*.log" -type f
慎用命令行工具的非标准选项
macOS 自带的 BSD 版本工具(sed、date、stat)和 Linux 的 GNU 版本参数不兼容:
-
sed -i '' 's/old/new/' file(macOS) vssed -i 's/old/new/' file(Linux)——统一写成sed -i.bak 's/old/new/' file && rm -f file.bak可兼顾 -
date -v+1d(BSD)不可用,改用date -d '+1 day' 2>/dev/null || date -v+1d 2>/dev/null并优先测试 GNU 语法 - 避免
stat -c "%y"(GNU)或stat -f "%Sm"(BSD),改用ls -ld或 Python 一行:python3 -c "import os; print(os.path.getmtime('$file'))"
必要时用 Python 做兜底路径操作
Shell 天然不擅长复杂路径逻辑。当涉及嵌套、符号链接解析或跨文件系统判断时,直接调 Python 更稳:
- 获取真实绝对路径:
SCRIPT_DIR=$(python3 -c "import os; print(os.path.realpath(os.path.dirname('$0')))") - 拼接路径:
DATA_PATH=$(python3 -c "from pathlib import Path; print(Path('$SCRIPT_DIR').joinpath('data', 'input.txt'))") - 检查路径是否存在且为目录:
python3 -c "from pathlib import Path; exit(0 if Path('$TARGET').is_dir() else 1)"










