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格式。
notion image
从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确实是返回失败,但是我们仍能从标准输出中得到结果,这说明该脚本至少被执行过一次。
这个问题我在:
  1. https://stackoverflow.com/questions/12296308/shell-script-working-fine-without-shebang-line-why
  1. https://github.com/zsh-users/zsh/blob/a66e92918568881af110a3e2e3018b317c054e4a/Src/exec.c#L630
找到答案:当zsh运行失败时,会判断执行文件是否有可执行权限,若有则检查其是否为一个缺少shabang的脚本文件,若是则默认使用/bin/sh 执行该脚本。
 
Loading...

© ZENOTME 2021-2025