`
totoxian
  • 浏览: 1074967 次
  • 性别: Icon_minigender_2
  • 来自: 西安
文章分类
社区版块
存档分类
最新评论

没有#!的bash脚本的执行

 
阅读更多

有些bash脚本写的不规范,没有在文件开头写#!,但是却能直接执行,可是如果看内核代码,shell脚本的加载函数中的开头就会判断,如果没有#!的话就会返回错误:
static int load_script(struct linux_binprm *bprm,struct pt_regs *regs)
{
...
if ((bprm->buf[0] != '#') || (bprm->buf[1] != '!') || (bprm->sh_bang))
return -ENOEXEC;
...
}
为何在linux上写bash脚本时文件开头不写#!也能成功调用?bash中执行一条键盘命令时调用的是shell_execve函数,该函数封装了很多逻辑:
int shell_execve (command, args, env)
{
execve (command, args, env);
if (errno != ENOEXEC) {
//非文件格式的错误,返回出错
} else {
int larray = array_len (args) + 1;
int i, should_exec = 0;
int fd = open (command, O_RDONLY);
if (fd != -1) {
unsigned char sample[80]; //读取文件头的80个字节,然后进行格式判断
int sample_len = read (fd, &sample[0], 80);
...//如果是空文件,则正确返回,bash容忍这种情况
if (sample_len > 0 && sample[0] == '#' && sample[1] == '!')
return (execute_shell_script(...));//执行shell脚本,其实现过程几乎和内核的script_format结构对象中的

load_binary回调函数一模一样,主要用于不识别#!的操作系统
else if (check_binary_file (sample, sample_len))
//如果是二进制文件,则bash是不会逐行帮助执行的,出错返回
}
...//bash会帮你执行command:
/*
args[0] = shell_name; //就是本shell的全路径
args[1] = command; //要执行的脚本
execve (shell_name, args, env); //重新执行
*/
}
以下是上述shell_execve函数依赖的帮助函数和一些宏定义:
由于bash是通过字符的可见性来判断是否是二进制文件的,由于空格/制表符等也是不可见的字符,然而它们确实是属于文本ascii码的,因此需要单独进行过滤:
#define isspace(c) ((c) == ' ' || (c) == '/t' || (c) == '/n' || (c) == '/f')
文本字符包括字母字符,数字字符以及除此之外的可以打印字符:
#define isprint(c) (isletter(c) || digit(c) || ispunct(c))
判断读取的80个字节是否全部是文本字符,只要有一个不是就将该文件判定为二进制文件,虽然前80字节的字符是文本不能保证后面的就一定是文本,可是bash毕竟需要做出一个权衡和一个假设:
int check_binary_file (sample, sample_len)
{
for (i = 0; i < sample_len; i++) {
if (sample[i] == '/n')
break;
if (!isspace (sample[i]) && !isprint (sample[i]))
return (1);
}
return (0);
}
因此如果执行一个空文件,将会看到什么也不输出,如果执行一个非linux可执行的二进制文件比如cer格式的二进制证书,那么内核将返回ENOEXEC,接下来bash会尝试执行之,然后最终返回一个EX_BINARY_FILE错误,打印“cannot execute binary file”,如果执行一个文件头不是#!的文本文件,同样内核会返回一个ENOEXEC错误,但是bash却可以在shell_execve的后续执行中成功直接执行,可是如果在一个二进制文件的头部增加80字节或者80字节以上的文本,那么根据shell_execve的逻辑,bash也会将之作为脚本来分行执行,然后就会大错特错,因此虽然有的时候脚本中不写#!也能直接执行,但是要知道那可是bash本身帮你执行的,而不是内核直接执行的,起码执行绪会先从内核错误返回,然后继续shell_execve的后面的部分,确实稍微影响了效率,因此最好还是写上标准的#!,况且有的shell并不会像bash这么智能地重新解释执行命令。

分享到:
评论

相关推荐

    shell中第一行#!_bin_bash的作用

    ### Shell脚本中的第一行“#!_bin_bash”的作用详解 #### 一、引言 在Shell脚本编程中,我们经常会看到脚本的第一行是`#!...希望本文能帮助大家更深刻地理解Shell脚本执行的关键环节,并在实践中加以运用。

    Matlab 守护进程:一个 Bash 脚本和 Mex 程序,它允许针对后台 Matlab 会话编写 #! 风格的脚本。-matlab开发

    不幸的是,Mathworks 并未将 Matlab 设计为像典型的 Unix 解释器那样运行,即... 的执行时间脚本,提供的 Bash 脚本建立一个 Matlab 的后台会话,并根据需要重新使用这个会话。 请参阅“readme.html”进行安装和评论。

    bash脚本基础实例

    **Bash脚本基础实例详解** Bash,全称Bourne-Again SHell,是Linux和类Unix系统中的默认命令行解释器。它是一种强大的工具,允许用户通过编写脚本来自动化日常任务,提高工作效率。以下我们将通过五个基础实例,...

    dcsh:#!usrlocalbindcsh > #!binbash

    Shebang是用来指定脚本应该由哪个解释器执行的指令。`/usr/local/bin/dcsh`可能是一个自定义的或非标准的shell,如`dcsh`,而`/bin/bash`是通用的Bash shell。 描述 "概念证明 这是目前的概念证明,不应在生产环境...

    bash脚本编写教程

    【Bash脚本编写教程】深入讲解 Bash(Bourne-Again SHell)是Linux和Unix系统中最常用的Shell之一,它提供了丰富的命令行工具和脚本编程能力。对于初学者来说,学习Bash脚本编写是非常有价值的,因为这能帮助你自动...

    bash脚本编写教程简易教

    在Bash脚本中,我们可以使用这些命令来控制脚本的执行流程,实现复杂的逻辑操作。 总结 Bash脚本编写是Linux系统中的一种重要的编程技术。本文涵盖了Bash脚本编写的基本概念、变量、命令和流程控制等方面的知识点...

    高级Bash脚本编程指南 操作系统 - Linux - 高级Bash脚本编程指南.zip

    Bash脚本是一种文本文件,其中包含了可执行的Shell命令。它允许你自动化日常任务,例如文件管理、系统监控、数据处理等。脚本的开头通常会声明其解释器,即`#!/bin/bash`,这告诉系统使用Bash来执行该脚本。 在Bash...

    30分钟搞定BASH脚本编程

    ### BASH脚本编程基础与实战案例解析 #### 标题理解:30分钟搞定BASH脚本编程 本文档的标题“30分钟搞定BASH脚本编程”旨在传达一种高效学习的理念,即通过简短的时间内掌握BASH脚本的基础知识与实际应用技巧。...

    bash脚本编程详解

    #### 二、Bash脚本的建立与执行 **2.1 Shell块的建立** Shell脚本是由一系列命令组成的文本文件。这些命令按照预定的顺序被执行。在编写脚本时,可以通过注释 (`#`) 来添加说明文字。Shell脚本的结构通常包括: 1...

    30分钟搞定BASH脚本编程.txt

    从给定的文件信息中,我们可以提取出关于BASH脚本编程的重要知识点,这些知识点涵盖了从基础知识到高级功能的广泛范围。 ### BASH脚本基础 #### Hello World示例 脚本通常以`#!/bin/bash`行开头,这被称为shebang...

    Linux Bash脚本大全.pdf

    ### Linux Bash脚本大全知识点概览 #### 一、引言 - **Shell的重要性:** Shell作为用户与操作系统之间的交互接口,在Linux/UNIX系统中扮演着极其重要的角色。特别是Bash(Bourne Again Shell),它是当前最流行的...

    Bash 脚本编程基础,shell 脚本学习

    ### Bash 脚本编程基础知识点 #### 一、Shell 概述与分类 - **定义**:Shell 是一种命令行解释器,同时也是 Linux 和 Unix 操作系统的用户界面。它接收用户的输入,并将这些命令传递给操作系统进行处理。 - **语言...

    一个简单的Bash脚本示例,该脚本旨在设置ROS环境、构建ROS包,并运行一个简单的ROS节点

    ### Bash脚本示例解析与ROS环境配置详解 #### 一、引言 本文将详细介绍一个简单的Bash脚本示例,该脚本主要用于设置ROS(Robot Operating System)环境、构建ROS包,并运行一个简单的ROS节点。对于机器人开发者来...

    高级Bash脚本编程指南

    ### 高级Bash脚本编程指南:深入解析与实践 #### 一、引言:为何选择Bash脚本? Bash(Bourne Again Shell)作为Linux和大多数Unix系统中广泛使用的shell环境,不仅是系统与用户之间的桥梁,更是自动化任务、流程...

    linux shell脚本编程

    这段代码意味着脚本应该由`bash`解释器来执行。 #### 三、Shell脚本的核心要素 ##### 3.1 Exit和Exit Status 在Shell脚本中,`exit`命令用于终止脚本的执行,并返回一个退出状态值。这个值通常用于表示脚本是否...

Global site tag (gtag.js) - Google Analytics