Shell 脚本报错 unexpected token 语法错误怎么排查

文章导读
遇到 Shell 脚本报 unexpected token 错误,最常见的原因是脚本在 Windows 下编辑过,导致换行符不兼容,其次才是语法书写错误或 Shell 版本不支持。
📋 目录
  1. 典型报错特征
  2. 命令速用版
  3. 为什么会这样
  4. 分步处理
  5. 怎么验证是否生效
  6. 常见坑
  7. 参考来源
A A

遇到 Shell 脚本报 unexpected token 错误,最常见的原因是脚本在 Windows 下编辑过,导致换行符不兼容,其次才是语法书写错误或 Shell 版本不支持。

先说结论:优先排查文件换行符格式,确认是 Unix 格式后再检查语法空格和解释器版本。

  • 先确认:文件是否包含 Windows 换行符(^M 或\r)
  • 先处理:使用 dos2unix 或 sed 清除多余字符(操作前建议备份)
  • 再验证:通过 bash -n 检查语法是否通过

典型报错特征

此类错误通常伴随具体的行号提示,典型报错信息如下:

./script.sh: line 2: syntax error near unexpected token $'\r'

./script.sh: line 5: syntax error near unexpected token `('

若看到 $'\r' 或错误指向行尾,极大概率是换行符问题;若指向特定符号,则可能是空格或括号缺失。

命令速用版

如果急着修复,请先备份原文件,再尝试以下命令清除隐藏字符并检查语法:

cp script.sh script.sh.bak

Linux 系统:

sed -i 's/\r//g' script.sh

macOS 系统:

sed -i '' 's/\r//g' script.sh

Shell 脚本报错 unexpected token 语法错误怎么排查

语法检查:

bash -n script.sh

如果有安装 shellcheck,推荐运行:

shellcheck script.sh

为什么会这样

Linux 和 Windows 对换行符的定义不同。Windows 使用回车 + 换行(CRLF,即\r\n),而 Linux 只使用换行(LF,即\n)。当脚本在 Windows 下编写保存后传到 Linux,行尾的\r 会被 Shell 解析为命令的一部分,导致报 unexpected token 错误。

此外,Shell 对语法空格非常敏感,例如条件判断 [ ] 内部两侧必须有空格,否则会被视为命令名。如果脚本指定了#!/bin/sh 但实际使用了 Bash 特性(如数组),也会因版本过低报错。

分步处理

1. 检查并转换换行符

推荐使用 file 命令快速查看文件格式:

file script.sh

若输出包含 CRLF 或 DOS,说明格式不对。也可使用 cat -v 查看是否有^M 字符:

cat -v script.sh

Shell 脚本报错 unexpected token 语法错误怎么排查

确认后可使用工具转换:

dos2unix script.sh

若使用 vim,注意二进制模式操作有风险,建议仅在熟悉时使用:

vim -b script.sh

在 vim 中替换删除^M(Ctrl+v 然后 Ctrl+m 输入^M):

:%s/^M//g

2. 检查语法空格与括号

检查 if 语句或条件判断中,方括号 [ ] 内侧是否有空格。例如 [ $? -ne 0 ] 是正确的,而 [$?-ne 0] 会报错。函数定义时,函数名后的 () 与花括号 { 之间建议保留空格或换行。

3. 确认 Shell 解释器版本

查看脚本第一行是否指定了正确的解释器,建议明确写为:

#!/usr/bin/env bash

Shell 脚本报错 unexpected token 语法错误怎么排查

如果脚本用到了数组等高级特性,确保系统 Bash 版本支持,避免使用 sh 执行脚本。

怎么验证是否生效

修复后,先不要直接运行,使用语法检查模式确认没有错误:

bash -n script.sh

如果没有输出,说明语法检查通过。然后再赋予执行权限并运行:

chmod +x script.sh

./script.sh

观察是否还有报错,或者使用 cat -v 确认文件中已无^M 符号。

常见坑

1. 直接用 sh 运行:sh 通常链接到 dash 或旧版 bash,不支持某些语法,应显式使用 bash 调用。

2. 复制粘贴引入隐藏字符:从网页或文档复制代码到脚本时,可能带入不可见字符,建议手动输入关键行。

3. 忽略错误行号:报错信息通常会提示错误发生的行号,但有时是因为上一行缺少分号或引号未闭合,需向上排查。

4. 修改前未备份:使用 sed -i 直接修改文件无备份,可能导致脚本损坏,建议先 cp 备份。

参考来源

  • GNU Bash 官方文档
  • Linux Shell 脚本编程规范
  • shellcheck 静态分析工具说明