shell脚本常见错误排查

  本文记录写新手在 shell 脚本的过程中经常遇到的报错与逃坑方案。

常见报错

  这里列举一些新手经常遇到的报错。

$’\r’: command not found或$’\r’: 未找到命令

原因

  用 Windows 的同学,经常会遇到这个问题,比如我,习惯性在桌面新建 .txt 文件,更改后缀名为 .sh,然后用 notepad++ 进行打开。这是由于 Windows 与 Unix 下换行符的差异导致的,Windows 默认新建 .txt 的文件格式为 dos 文件格式,Windows 下换行符其实为”\CR\LF”,Unix 下换行符为”\CR”。

解决方法

方法一: notepad++ 打开脚本,右键 notepad++ 右下角的 Windows(CR LF) 修改为 Unix 保存即可。这里最好在 notepad++ 中选择 设置-首选项-新建的”格式”中选择”Unix(LF)”。
方法二: 使用 dos2unix 转换格式

1
2
yum install dos2unix		# CentOS 
apt-get install dos2unix # Ubuntu

执行:

1
dos2unix filename  

即可。

[-d: command not found或[-d: 未找到命令

  出现这个报错一般是部分新手不知道 if 语句两边的中括号要加空格。如下列代码:

1
2
3
4
#!/bin/sh  
if [-d /etc]; then
echo "ok"
fi

就会出现这个报错。 改成如下即可:

1
2
3
4
#!/bin/sh  
if [空格-d /etc空格]; then
echo "ok"
fi

[:badinterpreter:Nosuchfileordirectory]

  这是因为在 Windows 下编辑,传到 Linux 下执行,由于编码不一致,导致的:
在 DOS/windows 里,文本文件的换行符为 rn,而在 nix 系统里则为n,所以DOS/Windows 里编辑过的文本文件到了 nix 里,每一行都多了个 ^M

解决方法:

1
2
3
vi:%s/r//g:%s/^M//g # (^M输入用Ctrl+v,Ctrl+m)
#
vi:set ff=unix

引用变量时,变量中的’*’字符被解释器运行了

先看范例:

1
2
JAVA_OPTIONS='-Dspring.session.redis.cleanup-cron="0 * * * * ?"'
echo $JAVA_OPTIONS

执行该脚本时,结果为:

1
-Dspring.session.redis.cleanup-cron="0 1.sh mysql.socket tmpfile

后面的 ‘‘ 变成了脚本目录下的文件名,即 ‘‘ 被解释器运行了。
要避免这种情况只需要在引用变量的时候,用双引号包裹变量即可:

1
2
JAVA_OPTIONS='-Dspring.session.redis.cleanup-cron="0 * * * * ?"'
echo "$JAVA_OPTIONS"

执行后结果为:

1
-Dspring.session.redis.cleanup-cron="0 * * * * ?"

达到预期的效果。

Tips

脚本检验

  脚本在运行前最好检查一下语法错误:

1
2
sh -n filename  # 不运行脚本,只检查语法错误  
sh -x filename # 运行并跟踪脚本执行过程

这里也可以在脚本的开头加入 set -x 来达到与上述 sh -x 同样的效果。
关于这方面详细可以参考 shell脚本——调试(-n / -x /-c)

ShellCheck 工具

  ShellCheck 是一款 shell 脚本静态检查工具,帮助查出错误,同时也会给出一些建议。