Shell的秘密
date
slug
tags
summary
type
status
今天遇到一件奇怪的事,以上的脚本在不同的执行模式下会有不同的输出:
可以看到,以上错误的本质原因是不同shell对语法的支持情况不同,导致该脚本只能在bash中顺利执行。通过
echo $SHELL
可以看到当前的SHELL的版本是zsh。但是为什么除了显式执行的情况,有些情况会触发其他SHELL的启动?Script脚本的执行
首先,我们通过strace来跟踪
./test.sh
发生了什么事?可以看到本质就是对execve的系统调用?Wait,execve系统调用可以处理脚本?是的,Linux支持注册各种格式,每个格式会提供一个
fmt
->
load_binar
的方法尝试加载程序,execve会将程序尝试按序用所有注册的格式进行加载,加载成功即进入运行。检查的代码可见如下:通过register_binfmt的跟踪可以发现linux支持经典的elf格式,以及可以看到最下方的script格式。
从script格式的load_binary可以看到其会首先检查有没有shabang(#!),#!用于指定脚本的解释器,若没有,linux无法知道用哪种解释器,则会运行失败。
通过下面一个简单的程序可以验证这一点,test.sh确实无法被成功启动。test.sh必须被显式传入一个解释器(如:
/bin/sh test.sh
)进行执行。.和source
.和source是shell的内置命令,通常用于在当前的shell环境执行脚本。因此通过.和source执行test.sh得到的输出与使用/bin/zsh执行的结果一致。
./test.sh
最诡异的情况是
./test.sh
,从strace的追逐结果看,execve
确实是返回失败,但是我们仍能从标准输出中得到结果,这说明该脚本至少被执行过一次。这个问题我在:
找到答案:当zsh运行失败时,会判断执行文件是否有可执行权限,若有则检查其是否为一个缺少shabang的脚本文件,若是则默认使用
/bin/sh
执行该脚本。Loading...