BASH and SH in SHELL scripts

一、执行脚本的现象

为了测试一个小的功能,写了一个小脚本,类似的内容如下:

复制代码
#!/bin/sh

echo "start  api  test ......"

for((i=1;i<=10;i++));
do
echo "cur id :" $i;
done
echo "end."

执行一下,"./testEx.sh",结果报一个错误"sh: 5: Syntax error: Bad for loop variable"。说实话对脚本的编写还是相对少很多的,这个简单的错误勾起了探索一下的想法 。于是把执行的方式改变了下,"bash testEx.sh",正常运行。然后把文件内容中的"#!/bin/sh"修改为"#!/bin/bash",即使使用"./testEx,sh",也可以正常执行。下面就分析一下原因,脚本大佬可以滑走了。

二、原因和解决

通过上述的执行,发现其实问题的产生就在于是使用sh还bash。那么系统是如何区别这两种脚本的呢?首先执行一个命令看看当前默认的脚本执行解释器:

复制代码
#echo $0
bash

再执行一下命令,看看当前支持哪些脚本的解释器:

复制代码
tests$ cat /etc/shells
# /etc/shells: valid login shells
/bin/sh
/bin/bash
/usr/bin/bash
/bin/rbash
/usr/bin/rbash
/usr/bin/sh
/bin/dash
/usr/bin/dash

也可能通过命令来查看具体的执行解释器位置:

复制代码
tests$ ls /bin/*sh -l
-rwxr-xr-x 1 root root   27016  5月 31  2023 /bin/avahi-publish
-rwxr-xr-x 1 root root 1396520  1月  7  2022 /bin/bash
-rwsr-xr-x 1 root root   44808 11月 24  2022 /bin/chsh
-rwxr-xr-x 1 root root    6963 10月 13  2023 /bin/c_rehash
-rwxr-xr-x 1 root root  125688  3月 23  2022 /bin/dash
-rwxr-xr-x 1 root root    5188  3月 25  2022 /bin/gettext.sh
-rwxr-xr-x 1 root root    2181  2月  7  2022 /bin/gvmap.sh
-rwxr-xr-x 1 root root    4373  5月 24  2023 /bin/instmodsh
-rwxr-xr-x 1 root root   39460  6月  7  2023 /bin/nvidia-bug-report.sh
-rwxr-xr-x 1 root root     900  6月  7  2023 /bin/nvidia-sleep.sh
-rwxr-xr-x 1 root root   14648  2月 16  2023 /bin/pax11publish
lrwxrwxrwx 1 root root       4  5月  5  2023 /bin/rbash -> bash
lrwxrwxrwx 1 root root      21  5月  5  2023 /bin/rsh -> /etc/alternatives/rsh
lrwxrwxrwx 1 root root       4  5月  5  2023 /bin/sh -> dash  #在本机为dash,而不是bash
-rwxr-xr-x 1 root root  846888  8月 24  2023 /bin/ssh
lrwxrwxrwx 1 root root       7  5月  5  2023 /bin/static-sh -> busybox
lrwxrwxrwx 1 root root       8  5月  5  2023 /bin/tclsh -> tclsh8.6
-rwxr-xr-x 1 root root     281  5月  8  2023 /bin/vmware-license-check.sh
-rwxr-xr-x 1 root root     288  5月  8  2023 /bin/vmware-license-enter.sh
-rwxr-xr-x 1 root root   14728  3月 25  2022 /bin/xrefresh

通过上述的命令可以发现,在系统中存在着多个脚本的解释器,默认的使用是bash。但随即又出来一个问题,不同写法和不同的执行方式,到底调用了哪种解释器?把这个弄清楚了,就可以解决问题了。仍然以最开初的例子为例,这里使用以下几种方式来编辑并执行:

1、使用bash testEx.sh执行:

复制代码
start  api  test ......
cur id : 1  

......  

cur id : 10  

end.

2、在脚本中指定#!/bin/bash,然后执行,结果同上。

3、默认执行,有可能需要增加执行权限,执行结果:

复制代码
 Syntax error: Bad for loop variable

4、脚本中不指定任何解释器,执行bash testEx.sh,正常执行并显示结果同1。

5、脚本中不指定任何解释器,默认执行,正常执行,结果同上。

上面的5种方式只有3这种情况会出异常,而在前面的命令中发现它调用的是sh->dash。明确使用bash的,正常执行,显示结果;未明确在脚本中指定的,使用系统默认的bash,所以结果均一致。

通过上述例子就可以明白 :如果使用bash执行脚本或者在脚本中指定bash脚本解释器(#!/bin/bash),则始终以bash脚本解释器来处理脚本;如果脚本 指定为"#!/bin/sh",则这个标准的解释器会调用其真正链接的解释器,在本文中它链接的是dash。使用默认执行则看系统默认的脚本解释器是如个即可。

三、扩展

"#!"体现在文件中就是一个2字节魔数,魔数开发者应该都清楚,就是代表文件类型的特殊标记,在此处即为可执行的脚本。在"#!"之后,一般是一个脚本解释器的路径,当然这个解释器可以是一个普通认知的解释器,如bash,sh,csh,dash等等,也可以是一个程序。这就看具体的应用方式了。比如下面的例子:

复制代码
#!/bin/cat
echo "Used cat!"

这个脚本使用Cat命令来处理,直接执行脚本"./testCat.sh",执行结果为(如果使用bash testCat.sh看看结果是什么?):

复制代码
#!/bin/cat
echo "Used cat!"

那么bash和sh在实际的应用中有什么不同呢?一个简单的说法是前者包括后者;或者说后者是前者的一个子集。从前面命令执行也可以看出,bash提供了对posix的支持。所以才可以将循环写成和C语言类似的方式。如果执行"/bin/bash --posix"则会发现它和"/bin/sh"执行的结果一致,这下就明白了吧,sh是bash的posix支持版。

四、总结

脚本用处真得很大,尤其在一些监控、测试的情况下,一个简单的小脚本就可以达到控制程序的目的。特别是粘连一些相关工具如Jenkins和部署时,可以极大的减少代码的工作量并迅速构建迅速部署。当然脚本的缺点也不少,最显著的就是不好调试,对一些复杂的函数和变量往往需要死记硬背。

建议大家都要好好学习一下脚本相关的知识,这样在服务端开发中,会大提高工作效率。原来总以为脚本是运维的事儿,后来才发现大谬。好好学习,犹未晚尔!

相关推荐
tf的测试笔记2 小时前
测试团队UI自动化实施方案
运维·自动化
TDD_06282 小时前
【运维】Centos硬盘满导致开机时处于加载状态无法开机解决办法
linux·运维·经验分享·centos
头孢头孢3 小时前
k8s常用总结
运维·后端·k8s
遇码3 小时前
单机快速部署开源、免费的分布式任务调度系统——DolphinScheduler
大数据·运维·分布式·开源·定时任务·dolphin·scheduler
爱编程的王小美3 小时前
Docker基础详解
运维·docker·容器
学习至死qaq4 小时前
windows字体在linux访问异常
linux·运维·服务器
IEVEl4 小时前
Centos7 安装 TDengine
运维·centos·时序数据库·tdengine
在野靡生.5 小时前
Ansible(4)—— Playbook
linux·运维·ansible
烨鹰5 小时前
戴尔电脑安装Ubuntu双系统
linux·运维·ubuntu
HX科技5 小时前
Debian系统_主板四个网口1个配置为WAN,3个配置为LAN
linux·运维·网络·debian