Shell 脚本报错$'\r': command not found 的完整排查与修复记录
在 Linux 服务器上执行一个名为 clear.sh 的清理脚本时,终端抛出了如下错误:
clear.sh: line 5: $'\r': command not found这是一个非常典型的跨平台换行符兼容性问题,常见于从 Windows 系统编写后上传到 Linux 环境执行的 Shell 脚本。
报错原因分析
该错误的根本原因是换行符格式不兼容。Windows 系统使用的是 CRLF(Carriage Return + Line Feed,即 \r\n )作为换行符,而 Linux/Unix 系统只识别 LF( \n )作为换行符。当脚本文件在 Windows 环境下编辑保存后,每一行末尾都会多出一个不可见的回车符 \r 。
Shell 解释器在执行脚本时,会将 \r 视为命令的一部分进行解析,由于 \r 并非有效的 Shell 命令,因此报出 $'\r': command not found 错误。其中 $'...' 是 Shell 的 ANSI-C 转义语法,用于表示不可见的控制字符。
原始脚本内容
出现问题的 clear.sh 脚本原始内容如下:
#!/bin/bash
echo "=== 清理 yum/dnf 缓存 ==="
yum clean all || dnf clean all
yum autoremove -y || dnf autoremove -y
echo -e "\n=== 清理 journal 日志 ==="
journalctl --vacuum-time=7d
echo -e "\n=== 清理临时文件 ==="
find /tmp -type f -atime +10 -delete
find /var/tmp -type f -atime +10 -delete
echo -e "\n=== 清理压缩旧日志 ==="
find /var/log -name "*.gz" -delete
echo -e "\n=== 清理 root 缓存 ==="
rm -rf /root/.cache/*
echo "清理完成!"该脚本的功能是清理系统缓存、日志和临时文件,涵盖 yum/dnf 缓存、journal 日志、/tmp 临时文件、旧日志压缩包以及 root 用户缓存目录。
修复方案一:sed 命令在线转换
在 Linux 服务器上直接使用 sed 命令去除每行末尾的回车符,这是最快捷的修复方式,无需安装额外工具:
sed -i 's/\r$//' clear.sh参数说明:
-i:直接修改原文件(in-place)s/\r$//:正则替换,将行尾的\r替换为空
转换完成后,赋予脚本执行权限并运行:
chmod +x clear.sh
./clear.sh修复方案二:编辑器修改换行格式
在 Windows 端的代码编辑器中直接将文件换行格式从 CRLF 切换为 LF,然后重新上传到服务器。
- VS Code 操作方式: 点击编辑器右下角状态栏中的
CRLF标识,在弹出的选项中选择LF,保存文件即可。 - Notepad++操作方式: 依次点击菜单栏「编辑」→「文档格式转换」→「转为 Unix (LF)」,然后保存文件。
传输注意事项: 使用 Xshell、WinSCP 等工具上传文件时,选择二进制传输模式可以避免传输过程中自动转换换行符导致的二次问题。
修复方案三:dos2unix 工具转换
使用专门的 dos2unix 工具进行换行符格式转换,这是 Linux 环境下处理 DOS 格式文件的标准工具:
# CentOS/RHEL 系统安装
yum install -y dos2unix
# 转换脚本文件
dos2unix clear.sh
# 赋予执行权限并运行
chmod +x clear.sh
./clear.shdos2unix 命令会自动将文件中的 CRLF 换行符转换为 LF 格式,同时保留文件的其他属性不变。
优化后的脚本版本
在修复换行符问题的基础上,对原脚本进行了逻辑优化,主要改进点在于对 yum 和 dnf 包管理器的存在性判断,避免因系统只安装其中一种而导致命令报错中断脚本执行:
#!/bin/bash
echo "=== 清理 yum/dnf 缓存 ==="
if command -v yum &> /dev/null; then
yum clean all
yum autoremove -y
elif command -v dnf &> /dev/null; then
dnf clean all
dnf autoremove -y
fi
echo -e "\n=== 清理 journal 日志 ==="
journalctl --vacuum-time=7d
echo -e "\n=== 清理临时文件 ==="
find /tmp -type f -atime +10 -delete
find /var/tmp -type f -atime +10 -delete
echo -e "\n=== 清理压缩旧日志 ==="
find /var/log -name "*.gz" -delete
echo -e "\n=== 清理 root 缓存 ==="
rm -rf /root/.cache/*
echo "清理完成!"优化后的脚本通过 command -v 检测包管理器是否存在,存在则执行对应清理命令,不存在则跳过,提升了脚本在不同发行版上的兼容性和健壮性。
小结
$'\r': command not found 是跨平台开发中极为常见的换行符兼容性问题。三种修复方案各有适用场景: sed 命令适合在服务器上快速修复已有文件;编辑器修改适合在开发阶段统一格式; dos2unix 工具适合批量处理大量 DOS 格式文件。无论采用哪种方式,核心目标都是将文件的换行符从 Windows 的 CRLF 格式转换为 Linux 的 LF 格式。
发布评论
评论列表 0



