sudo执行bash脚本报错"sudo: unable to execute"

同事传给我一个shell启动脚本,简单对比了一下线上脚本,判断没有问题,就上传到服务器上执行。执行需要使用sudo方式以root用户身份执行,但是遇到奇怪的问题,总是提示不能执行脚本:

$sudo /etc/init.d/my_service_script start
sudo: unable to execute /etc/init.d/my_service_script: Success

这个问题困扰了我,肉眼看脚本,一点都看不出语法和逻辑错误。并且这个脚本内容和线上已经在使用的脚本是完全一样的。

然而,当我不死心,先切换到root身份,然后不使用sudo而是直接运行脚本,则shell提示看出了问题:

#/etc/init.d/my_service_script start
-bash: /etc/init.d/my_service_script: /bin/bash^M: bad interpreter: No such file or directory

剔除了sudo影响,可以看到脚本中在#!/bin/bash解释器行末尾多出了^M符号,这是由于对方使用了Windows操作系统复制粘贴脚本,导致多出了隐含字符,影响了解释器路径。

如何显示出隐藏字符?

参考 How to Display Hidden Characters in vim? 可以通过以下指令在vim中检查隐藏字符:

:set listchars=eol:$,tab:>-,trail:~,extends:>,precedes:<
:set list

观察发现对方传输给我的shell脚本中,每一行末尾都显示了一个$符号。但是很奇怪,并没有看到^M

可以使用cat -v filename来显示详细的信息,包含隐藏字符。

参考 View line-endings in a text file,使用 :set list 也是只能看到$,实际上无法看到\r

DOS/Windows操作系统,换行符是\r\n,而在Linux/Unix换行符是\n

可以通过grep命令找出存在\r换行符的行

grep -r $'\r' *

这里-r参数可以递归扫描整个目录,$''则是c风格的escape。

如果是文本文件,可以通过tr命令移除 \r

tr -d $'\r' < filename>

也可以使用GNU sed

sed $'s/\r//' -i filename
  • 转换windows文档可以使用dos2unix命令:

dos2unix filename.txt

参考

Last updated