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和部署时,可以极大的减少代码的工作量并迅速构建迅速部署。当然脚本的缺点也不少,最显著的就是不好调试,对一些复杂的函数和变量往往需要死记硬背。

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

相关推荐
mounter6251 小时前
深度解析:Linux 内核为何要移除“直接映射” (Direct Map)?
linux·运维·服务器·security·linux kernel·direct mem map
AC赳赳老秦1 小时前
HR必备:OpenClaw批量筛选简历、发送面试通知,优化招聘流程
运维·人工智能·python·eclipse·github·deepseek·openclaw
NineData1 小时前
NineData亮相香港国际创科展InnoEX 2026,以AI加速布局全球市场
运维·后端
another heaven2 小时前
【Docker/虚拟机 深度对比Docker与虚拟机:原理、区别与最佳使用场景】
运维·docker·容器
带娃的IT创业者2 小时前
零停机迁移:如何将服务器成本从 $1432 降至 $233
运维·服务器·网络·成本优化·服务器迁移·零停机·hetzner
独自归家的兔2 小时前
2026年4月16日 Ubuntu系统 Docker 的安装与配置
运维·docker·容器
福老板的生意经3 小时前
从成本失控到ROI翻倍:企业数字化营销投放的落地路径与工具选型指南
大数据·运维·人工智能
va学弟3 小时前
Agent入门开发
java·运维·服务器·ai
殷紫川4 小时前
Docker Compose实战指南
运维·docker
j_xxx404_5 小时前
万字长文爆肝:彻底弄懂Linux文件系统(Ext2),从Inode、Block到Dentry核心机制全解析
linux·运维·服务器