关于sh脚本在windows编辑后传到服务器执行时出现报错-bash: xxx.sh: /bin/bash^M: bad interpreter: No such file or directory

解决办法

上一篇我们讲过定时备份数据库的脚本。刚好另一个服务器也需要部署同样的功能,于是我通过复制代码,在电脑上编辑好,保存为.sh文件,这时是在windows操作系统操作的。

完成后,传到Linux服务器去执行的时候,发现出现了报错

-bash: xxx.sh: /bin/bash^M: bad interpreter: No such file or directory

于是通过cat 去查看内容

[root@hcss-ecs-dd6b mymall]# cat -A ./backup.sh
#!/bin/bash^M$
# PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin^M$
# export PATH^M$
#M-fM-^UM-0M-fM-^MM-.M-eM-:M-^SM-gM-^TM-(M-fM-^HM-7M-eM-^PM-^M^M$
dbuser='root'^M$
#M-fM-^UM-0M-fM-^MM-.M-eM-:M-^SM-gM-^TM-(M-eM-/M-^FM-gM- M-^A^M$
dbpasswd='Jiang@2024'^M$
#M-iM-^\M-^@M-hM-&M-^AM-eM-$M-^GM-dM-;M-=M-gM-^ZM-^DM-fM-^UM-0M-fM-^MM-.M-eM-:M-^SM-oM-<M-^LM-eM-$M-^ZM-dM-8M-*M-fM-^UM-0M-fM-^MM-.M-eM-:M-^SM-gM-^TM-(M-gM-)M-:M-fM- M-<M-eM-^HM-^FM-eM-<M-^@^M$
dbname='mymall-v1'^M$
#M-eM-$M-^GM-dM-;M-=M-fM-^WM-6M-iM-^WM-4^M$
backtime=`date +%Y%m%d%H%M%S`^M$
#M-fM-^WM-%M-eM-?M-^WM-eM-$M-^GM-dM-;M-=M-hM-7M-/M-eM->M-^D^M$
logpath='/opt/mymall/backup/log'^M$
#M-fM-^UM-0M-fM-^MM-.M-eM-$M-^GM-dM-;M-=M-hM-7M-/M-eM->M-^D^M$
datapath='/opt/mymall/backup/backmysql'^M$
#M-fM-^WM-%M-eM-?M-^WM-hM-.M-0M-eM-=M-^UM-eM-$M-4M-iM-^CM-(^M$
echo M-bM-^@M-^X"M-eM-$M-^GM-dM-;M-=M-fM-^WM-6M-iM-^WM-4M-dM-8M-:${backtime},M-eM-$M-^GM-dM-;M-=M-fM-^UM-0M-fM-^MM-.M-eM-:M-^SM-hM-!M-( ${dbname} M-eM-<M-^@M-eM-'M-^K" >> ${logpath}/log.log^M$
#M-fM--M-#M-eM-<M-^OM-eM-$M-^GM-dM-;M-=M-fM-^UM-0M-fM-^MM-.M-eM-:M-^S^M$
for table in $dbname; do^M$
echo ${table}^M$
sleep 1m^M$
source=`mysqldump -u ${dbuser} -p${dbpasswd} ${table}> ${datapath}/${backtime}.sql` 2>> ${logpath}/mysqllog.log;^M$
^M$
#M-eM-$M-^GM-dM-;M-=M-fM-^HM-^PM-eM-^JM-^_M-dM-;M-%M-dM-8M-^KM-fM-^SM-^MM-dM-=M-^\^M$
if [ "$?" == 0 ];then^M$
cd $datapath^M$
#M-dM-8M-:M-hM-^JM-^BM-gM-:M-&M-gM-!M-,M-gM-^[M-^XM-gM-)M-:M-iM-^WM-4M-oM-<M-^LM-eM-0M-^FM-fM-^UM-0M-fM-^MM-.M-eM-:M-^SM-eM-^NM-^KM-gM-<M-)^M$
zip -r  ${table}${backtime}.zip ${backtime}.sql > /dev/null^M$
#M-eM-^HM- M-iM-^YM-$M-eM-^NM-^_M-eM-'M-^KM-fM-^VM-^GM-dM-;M-6M-oM-<M-^LM-eM-^OM-*M-gM-^UM-^YM-eM-^NM-^KM-gM-<M-)M-eM-^PM-^NM-fM-^VM-^GM-dM-;M-6^M$
rm -f ${datapath}/${backtime}.sql^M$
#M-eM-^HM- M-iM-^YM-$M-dM-8M-^CM-eM-$M-)M-eM-^IM-^MM-eM-$M-^GM-dM-;M-=M-oM-<M-^LM-dM-9M-^_M-eM-0M-1M-fM-^XM-/M-eM-^OM-*M-dM-?M-^]M-eM--M-^X7M-eM-$M-)M-eM-^FM-^EM-gM-^ZM-^DM-eM-$M-^GM-dM-;M-=^M$
find $datapath -name "*.zip" -type f -mtime +7 -exec rm -rf {} \; > /dev/null 2>&1^M$
echo "M-fM-^UM-0M-fM-^MM-.M-eM-:M-^SM-hM-!M-( ${dbname} M-eM-$M-^GM-dM-;M-=M-fM-^HM-^PM-eM-^JM-^_!!" >> ${logpath}/mysqllog.log^M$
else^M$
#M-eM-$M-^GM-dM-;M-=M-eM-$M-1M-hM-4M-%M-eM-^HM-^YM-hM-?M-^[M-hM-!M-^LM-dM-;M-%M-dM-8M-^KM-fM-^SM-^MM-dM-=M-^\^M$
echo "M-fM-^UM-0M-fM-^MM-.M-eM-:M-^SM-hM-!M-( ${dbname} M-eM-$M-^GM-dM-;M-=M-eM-$M-1M-hM-4M-%!!" >> ${logpath}/mysqllog.log^M$
fi^M$
done^M$

发现脚本的每一行的结尾都有个"^M"。 实际上是换行符,在windows中换行符为\n\r,而在Linux系统中则是\n, 因此需要将其中的\r替换为空,操作如下

[root@hcss-ecs-dd6b mymall]# sed -i "s/\r//" ./xxx.sh

再次通过cat 命令查看,就正常了。

[root@hcss-ecs-dd6b mymall]# cat -A ./xxx.sh
#!/bin/bash$
# PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin$
# export PATH$
#M-fM-^UM-0M-fM-^MM-.M-eM-:M-^SM-gM-^TM-(M-fM-^HM-7M-eM-^PM-^M$
dbuser='root'$
#M-fM-^UM-0M-fM-^MM-.M-eM-:M-^SM-gM-^TM-(M-eM-/M-^FM-gM- M-^A$
dbpasswd='Jiang@2024'$
#M-iM-^\M-^@M-hM-&M-^AM-eM-$M-^GM-dM-;M-=M-gM-^ZM-^DM-fM-^UM-0M-fM-^MM-.M-eM-:M-^SM-oM-<M-^LM-eM-$M-^ZM-dM-8M-*M-fM-^UM-0M-fM-^MM-.M-eM-:M-^SM-gM-^TM-(M-gM-)M-:M-fM- M-<M-eM-^HM-^FM-eM-<M-^@$
dbname='mymall-v1'$
#M-eM-$M-^GM-dM-;M-=M-fM-^WM-6M-iM-^WM-4$
backtime=`date +%Y%m%d%H%M%S`$
#M-fM-^WM-%M-eM-?M-^WM-eM-$M-^GM-dM-;M-=M-hM-7M-/M-eM->M-^D$
logpath='/opt/mymall/backup/log'$
#M-fM-^UM-0M-fM-^MM-.M-eM-$M-^GM-dM-;M-=M-hM-7M-/M-eM->M-^D$
datapath='/opt/mymall/backup/backmysql'$
#M-fM-^WM-%M-eM-?M-^WM-hM-.M-0M-eM-=M-^UM-eM-$M-4M-iM-^CM-($
echo M-bM-^@M-^X"M-eM-$M-^GM-dM-;M-=M-fM-^WM-6M-iM-^WM-4M-dM-8M-:${backtime},M-eM-$M-^GM-dM-;M-=M-fM-^UM-0M-fM-^MM-.M-eM-:M-^SM-hM-!M-( ${dbname} M-eM-<M-^@M-eM-'M-^K" >> ${logpath}/log.log$
#M-fM--M-#M-eM-<M-^OM-eM-$M-^GM-dM-;M-=M-fM-^UM-0M-fM-^MM-.M-eM-:M-^S$
for table in $dbname; do$
echo ${table}$
sleep 1m$
source=`mysqldump -u ${dbuser} -p${dbpasswd} ${table}> ${datapath}/${backtime}.sql` 2>> ${logpath}/mysqllog.log;$
$
#M-eM-$M-^GM-dM-;M-=M-fM-^HM-^PM-eM-^JM-^_M-dM-;M-%M-dM-8M-^KM-fM-^SM-^MM-dM-=M-^\$
if [ "$?" == 0 ];then$
cd $datapath$
#M-dM-8M-:M-hM-^JM-^BM-gM-:M-&M-gM-!M-,M-gM-^[M-^XM-gM-)M-:M-iM-^WM-4M-oM-<M-^LM-eM-0M-^FM-fM-^UM-0M-fM-^MM-.M-eM-:M-^SM-eM-^NM-^KM-gM-<M-)$
zip -r  ${table}${backtime}.zip ${backtime}.sql > /dev/null$
#M-eM-^HM- M-iM-^YM-$M-eM-^NM-^_M-eM-'M-^KM-fM-^VM-^GM-dM-;M-6M-oM-<M-^LM-eM-^OM-*M-gM-^UM-^YM-eM-^NM-^KM-gM-<M-)M-eM-^PM-^NM-fM-^VM-^GM-dM-;M-6$
rm -f ${datapath}/${backtime}.sql$
#M-eM-^HM- M-iM-^YM-$M-dM-8M-^CM-eM-$M-)M-eM-^IM-^MM-eM-$M-^GM-dM-;M-=M-oM-<M-^LM-dM-9M-^_M-eM-0M-1M-fM-^XM-/M-eM-^OM-*M-dM-?M-^]M-eM--M-^X7M-eM-$M-)M-eM-^FM-^EM-gM-^ZM-^DM-eM-$M-^GM-dM-;M-=$
find $datapath -name "*.zip" -type f -mtime +7 -exec rm -rf {} \; > /dev/null 2>&1$
echo "M-fM-^UM-0M-fM-^MM-.M-eM-:M-^SM-hM-!M-( ${dbname} M-eM-$M-^GM-dM-;M-=M-fM-^HM-^PM-eM-^JM-^_!!" >> ${logpath}/mysqllog.log$
else$
#M-eM-$M-^GM-dM-;M-=M-eM-$M-1M-hM-4M-%M-eM-^HM-^YM-hM-?M-^[M-hM-!M-^LM-dM-;M-%M-dM-8M-^KM-fM-^SM-^MM-dM-=M-^\$
echo "M-fM-^UM-0M-fM-^MM-.M-eM-:M-^SM-hM-!M-( ${dbname} M-eM-$M-^GM-dM-;M-=M-eM-$M-1M-hM-4M-%!!" >> ${logpath}/mysqllog.log$
fi$
done$

到这,脚本就可以正常执行了。

警告

在执行备份的过程中可能回出现一个警告

[Warning] Using a password on the command line interface can be insecure.

这个警告信息表明你在命令行界面使用密码是不安全的。因为在命令行中直接输入密码可能会被系统记录在历史文件中,或者被其他监听用户看到,从而可能导致安全隐患。

为了能够避免这种情况,你可以在sql中创建新的账户,分配权限来操作,这样避免了密码泄露,也可以去清除掉敏感的历史记录。

我这里暂时不用考虑安全问题,暂时先这样用着。