应统一换行符为lf、使用posix兼容语法、避免windows路径与命令、预检依赖工具,并以#!/bin/sh开头。具体包括:vs code中设行尾为lf,用dos2unix清理^m,用$pwd和$home代替windows路径,变量加双引号,条件用[ ]而非[[ ]],预检jq等命令是否存在。
☞☞☞AI 智能聊天, 问答助手, AI 智能搜索, 多模态理解力帮你轻松跨越从0到1的创作门槛☜☜☜

在Windows上写完脚本,一到Linux服务器就报错“/bin/bash^M: bad interpreter”,路径分隔符混乱、换行符不兼容、命令行为差异导致脚本直接瘫痪——这不是偶然,是跨平台脚本开发中最常踩的坑。
统一换行符与文件格式
用记事本或Notepad++保存.sh文件时,默认用CRLF(回车+换行),而Linux只认LF。Git提交后,即使本地能执行,远程Linux也会因解释器找不到入口而失败。
第一步:在VS Code中打开脚本 → 按Ctrl+Shift+P → 输入“Change End of Line Sequence” → 选择“LF”。
第二步:右下角状态栏确认显示“LF”,不是“CRLF”。【若显示CRLF,所有后续调试都白做】
第三步:在终端执行dos2unix your-script.sh(需先winget install dos2unix)。这一步不可跳过,它会批量清理隐藏的^M字符并重设权限位。
规避Windows特有路径与命令
不要用cd "C:\my\project",也不要用dir或copy,这些在Linux bash里根本不存在。脚本必须从第一行起就保持POSIX兼容性。
方法一:用$PWD代替绝对路径拼接,用cd "$(dirname "$0")/.." 回退到脚本所在目录的上级,这是最安全的定位方式。
方法二:检测运行环境并分流——但仅限必要场景。例如获取当前用户主目录,统一用$HOME,绝不用%USERPROFILE%或~(后者在某些sh变体中不可靠)。
方法三:用command -v判断命令是否存在,而不是直接调用。比如[ -n "$(command -v jq)" ] || { echo "jq not found"; exit 1; }。
Shell语法严格守界
Windows用户习惯用PowerShell写if ($a -eq $b),但bash里必须写成if [ "$a" = "$b" ];少一个空格、多一个$,脚本就在Linux上静默失败。
① 所有变量引用必须加双引号:"$PATH"、"${HOME}",否则含空格路径直接中断执行。
② 条件测试一律用[ ]而非[[ ]],前者是POSIX标准,后者是bash/zsh扩展,在dash(Ubuntu默认sh)中会报错。
③ 不使用source别名或函数定义前未声明function关键字——Linux的sh可能根本不认识function语法。
④ case语句结尾必须是esac,不能写成endcase或fi,这是硬性语法边界。
依赖工具预检与降级策略
脚本里调用jq、yq、fzf等工具时,不能假设它们已安装。Linux发行版差异极大,Alpine无glibc,CentOS默认没jq,Debian可能只有旧版。
运行前插入预检块:
for cmd in jq curl sed awk; do command -v "$cmd" >/dev/null 2>&1 || { echo "$cmd not available"; exit 1; }; done
对非核心依赖(如用于美化输出的tput),用if command -v tput >/dev/null; then tput setaf 2; fi包裹,避免因缺失中断主流程。
【切勿在脚本开头写#!/usr/bin/env bash——Linux容器环境常用dash,应固定为#!/bin/sh】











