本文转载自微信公众号「Linux常用命令」,作者妖生。转载本文请联系Linux常用命令公众号。
Shell脚本的后缀一般为“.sh”,脚本第一行一般都是指向执行Shell,例如“#!/bin/bash”。【#!】指定解释脚本执行的Shell。
执行Shell脚本有多种方式,我们可以直接使用【sh xx.sh】或者【bash xx.sh】来执行Shell,也可以使用【./xx.sh】、【/shell/xx.sh】,或者【source .sh】、【. xx.sh】。
它们有什么区别呢?测试脚本如下:
- [root@yaomm shell]# cat testShell.sh ## 查看演示Shell脚本
- #!/bin/bash
- cd /opt ; # 切换到/opt目录去
- pwds=`pwd`; # 查看当前路径
- pids=$$; # 查看当前进程
- users=`whoami`; # 查看当前用户
- echo "当前路径: ${pwds},当前进程PID:${pids},当前用户: ${users}"
sh方式执行(也可以使用bash):
- [root@yaomm shell]# echo $$ ## 查看当前cli(命令行)界面的进程号
- 22524 ## 每次登录Shell时打开的Shell界面进程号
-
- [root@yaomm shell]# sh testShell.sh ## 使用bash执行
- 当前路径: /opt,当前进程PID:10836,当前用户: root ## 输出当前切换路径、进程号、用户名
- [root@yaomm shell]# echo $users ## 子Shell中变量打印为空
相对路径方式执行(也可以使用绝对路径):
- [root@yaomm shell]# ./testShell.sh ## 使用路径执行,没有权限
- -bash: ./testShell.sh: Permission denied ## 没有执行权限
- [root@yaomm shell]# chmod +x testShell.sh ## 赋予执行权限
- [root@yaomm shell]# ./testShell.sh ## 使用路径执行
- 当前路径: /opt,当前进程PID:10873,当前用户: root ## 与bash执行的结果类似
- [root@yaomm shell]# echo $users ## 子Shell中变量打印为空
source方式执行(也可以使用点.):
- [root@yaomm shell]# source testShell.sh ## 使用source执行
- 当前路径: /opt,当前进程PID:22524,当前用户: root ## 进程号
- [root@yaomm opt]# ## 看到当前目录已经被切换到/opt下了
- [root@yaomm opt]# echo $users ## source执行,子Shell中变量被赋值
- root ## $users成为全局环境变量,不过重新登陆Shell后还是会消失
sh、source不需要执行权限就可以运行Shell脚本,为什么?因为Shell脚本只是作为一个参数传递到sh、bash、source命令中,使用的是bash这些脚本的权限。而路径执行,则使用的是被执行脚本文件本身的权限,所以需要赋权x。
sh与source执行也是有区别的,sh执行脚本会打开(fork)一个子进程(也叫子Shell、Sub Shell),Shell脚本内的环境变化不会影响到当前Shell进程(父进程、父Shell)。
source不创建Sub Shell,在当前Shell环境下读取并执行脚本文件中的命令,相当于顺序读取并执行“.sh”文件里面的命令。
还有其他执行脚本的方式,不常用,不再赘述。
最后,用一张表来总结下,Shell执行的几种方式和区别。
执行命令 | 示例 | 权限 | 打开子进程 | 说明 |
---|---|---|---|---|
sh、bash | bash test.sh、h test.sh | 不需要 | 是 | sh、bash都是使用/usr/bin/bash |
./、/ | ./test.sh、/shell/test.sh | 需要 | 是 | 相对路径、绝对路径执行,需要有脚本文件的执行权限 |
.、source | . test.sh 、source test.sh | 不需要 | 否 | 点+空格等同source,source执行脚本相当于把脚本中语句逐行读取并在命令行界面执行 |
<、| | sh>test.sh、cat tst.sh | bash | 不需要 | 是 | 对有参数的脚本不支持 |
exec | exec ./test.sh | 需要 | 否 | 替换当前进程资源,不要在命令行界面执行,否则登录Shell界面会被直接关闭 |