技术标签: python Linux linux 计算机系统 shebang
我们知道,一个C程序经过预处理、编译、汇编、链接就会得到一个二进制可执行文件,这种文件在Linux中叫做ELF文件。比如我们有一个C源代码hello.c
:
#include <stdio.h>
int main(int argc, char** argv){
printf("Hello !\n");
}
我们编译得到 hello
文件,并用file
命令可以查看到生成的二进制可执行文件的信息:
gcc hello.c -o hello
file hello
# 输出:
# hello: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=cf2738fd1715f096d4b0e0e4b264146b78b454b1, not strippe
确实是ELF文件,我们可以直接执行它:
./hello
# 输出:
# Hello
这是我们常见的,可以理解的,链接后的可执行文件就是可以直接运行,就像我们在Windows上双击打开一个exe文件那样自然。那么,脚本可执行文件又是怎么一回事呢?
脚本可执行文件也可以像运行二进制可执行文件那样来直接运行它。我们知道shell、python等属于脚本语言。令我们好奇的是,脚本程序如 train.py
等看上去只是一个文本文件,为什么也能直接被执行呢 ?
我们知道,想要运行一个脚本文件,我们需要指定一个解释器。通常,我们有两种方式来指定脚本文件的解释器:
bash run.sh
,python train.py
等。#!
。比如:#!/bin/bash
,#!/home/song/bin/python
等。Shebang通常出现在类Unix系统的脚本中第一行,作为前两个字符。在Shebang之后,可以有一个或数个空白字符,后接解释器的绝对路径,用于指明执行这个脚本文件的解释器。在直接调用脚本时,系统的程序载入器会分析 Shebang 后的内容,将这些内容作为解释器指令,并调用该指令,将载有 Shebang 的文件路径作为该解释器的参数,执行脚本,从而使得脚本文件的调用方式与普通的可执行文件类似。例如,以指令#!/bin/sh
开头的文件,在执行时会实际调用 /bin/sh
程序(通常是 Bourne shell 或兼容的 shell,例如 bash、dash 等)来执行。
由于 # 符号在许多脚本语言中都是注释标识符,这既是偶然,也是必然。Shebang 的内容会被这些脚本解释器自动忽略。 在 # 字符不是注释标识符的语言中,例如 Scheme,解释器也可能忽略以 #! 开头的首行内容,以提供与 Shebang 的兼容性。
实际上,#!
两个字符的ASCII码是两个magic字符,当类UNIX操作系统看到一个文件以这两个字符开头,会将这个文件当做是可执行文件,并且按照其后的解释器来执行它(需要有执行权限)。这时,操作系统实际上加载的是 #!
后面跟的那个二进制文件(即解释器),然后将脚本文件的文本内容作为参数传给这个二进制文件。这一点可以通过观察脚本可执行文件运行使得strace结果中的execve
来验证。
Shebang的一些具体用法和注意事项:
bad interpreter: Permission denied
。如果#!指定的解释程序不是一个可执行文件,那么指定的解释程序会被忽略,转而交给当前的SHELL去执行这个脚本。bad interpreter: No such file or directory
。注意:#!之后的解释程序,需要写其绝对路径(如:#!/bin/bash
),它是不会自动到环境变量PATH
中寻找解释器的。要用绝对路径是因为它会调用系统调用execve
,这可以用strace工具来查看。chmod +x [filename]
来添加可执行权限。bash test.sh
,python train.py
这样的命令来执行脚本,那么#!这一行将会被忽略掉,解释器当然是用命令行中显式指定的解释器。我们来试一下,先创建一个py文件world.py
,并直接写入为:
print('World !')
我们可以通过在命令行指定python解释器来运行,就像我们一直做的那样:
python world.py
# 输出:
# World !
但是,当我们想像运行二进制可执行文件那样来运行它:
./world.py
# 输出:
# -bash: ./world.py: Permission denied
首先会受到一条没有执行权限的命令,如上。这很正常,因为我们创建的时候它是一个文本文件嘛。我们通过 chmod
来使得它可执行,并再次尝试运行它:
chmod +x world.py
./world.py
# 输出:
# ./world.py: line 1: syntax error near unexpected token `'World !''
# ./world.py: line 1: `print('World !')'
问题出现了,和我们之前讨论的一样,由于我们没有通过Shebang来指定脚本的解释器,系统默认用了Shell来解释,那我们的python语法自然是不对的。那这时,想要像运行二进制可执行文件那样去运行它,必须请出我们的Shebang来帮忙在文件内指明解释器的绝对路径。更改world.py
为:
#!/home/song/anaconda3/envs/JJ_env/bin/python
print("World")
这时我们再来运行:
./world.py
# 输出:
# World !
就可以了。我们还可以通过 file
命令再来看一下 world.py
的文件信息:
file world.py
# 输出:
# world.py: a /home/song/anaconda3/envs/JJ_env/bin/python script, ASCII text executable
我们看到该文件是一个ASCII text executable
,即 ”文本可执行文件“。不同于ELF二进制可执行文件,但也是可执行文件。也就是说,在Linux的世界中,可执行文件不只有ELF一种。
另外,由于Linux系统对后缀名并不严格要求,我们可以直接将world.py
改为world
,这样也是可以的,然后就可以通过将world
这个脚本可执行文件放到PATH
环境变量下,从而将world
直接作为一个命令来使用啦!具体可参考笔者另一篇介绍Linux常用环境变量的博客。
总结一下:Linux中除了ELF二进制可执行文件之外,还有脚本可执行文件,要想让脚本可执行文件直接像二进制可执行文件一样运行,而不需在命令行中指定解释器,需要在脚本文件头通过Shebang !#
来指定解释器的绝对路径。Shebang的一些具体的注意事项在上文中已经指出。另外,通过将可执行文件(二进制、脚本都可)添加到PATH
环境变量的可执行文件搜索目录下,可将在命令行中通过命令来直接使用这些可执行文件。
Ref:
https://blog.csdn.net/u012294618/article/details/78427864
文章浏览阅读106次。BASE64编码算法不算是真正的加密算法。 MD5、SHA、HMAC这三种加密算法,可谓是非可逆加密,就是不可解密的加密方法,我们称之为单向加密算法。我们通常只把他们作为加密的基础。单纯的以上三种的加密并不可靠。 BASE64 按照RFC2045的定义,Base64被定义为:Base64内容传送编码被设计用来把任意序列的8位字节描述为一种不易被人直接识别的形式。(The ..._base 64编码 和mad5 和雪花算法
文章浏览阅读1.1k次。IP地址(Internet Protocol Address)是互联网协议地址的简称,是互联网通信的基础,互联网上每一个网络设备的唯一标识符每个在线的设备都需要一个IP地址,这样才能在网络中找到它们并进行数据交换。IP地址有很多种类型,今天跟大家简单分享一下住宅IP、家庭宽带IP以及原生IP的区别。住宅IP通常是指由互联网服务提供商(ISP)分配给家庭的或小型办公室使用的互联网连接IP地址,并可能随着网络连接的变化而变化。此类IP地址主要用于日常网络活动,如浏览网页、发送接收电子邮件、上网冲浪等。
文章浏览阅读2.6w次,点赞14次,收藏30次。如何更改layui form表单位置,宽度,颜色等_layui-form-item 宽度
文章浏览阅读612次。写的非常好_pagraph: scaling gnn training on large graphs via computation-aware caching
文章浏览阅读2.7w次,点赞61次,收藏285次。很炫酷的html代码:<!DOCTYPE html><html xmlns="http://www.w3.org/1999/xhtml" lang="en"><head><title>star</title><script type="text/javascript">window.onload = function () {C = Math.cos; // cache Math objectsS = Math.si.._炫酷的html
文章浏览阅读204次。题干:C国的死对头A国这段时间正在进行军事演习,所以C国间谍头子Derek和他手下Tidy又开始忙乎了。A国在海岸线沿直线布置了N个工兵营地,Derek和Tidy的任务就是要监视这些工兵营地的活动情况。由于采取了某种先进的监测手段,所以每个工兵营地的人数C国都掌握的一清二楚,每个工兵营地的人数都有可能发生变动,可能增加或减少若干人手,但这些都逃不过C国的监视。 中央情报局要研究敌人究竟演习什...
文章浏览阅读2.3k次。题目描述对数字,字符,数字串,字符串,以及数字与字符串组合进行倒序排列。字符范围:由 a 到 z, A 到 Z,数字范围:由 0 到 9符号的定义:“-”作为连接符使用时作为字符串的一部分,例如“20-years”作为一个整体字符串呈现;连续出现 2 个 “-” 及以上时视为字符串间隔符,如“out--standing”中的”–“视为间隔符,是 2 个独立整体字符串”out”和”standing”;除了 1,2 里面定义的字符以外其他的所有字符,都是非法字符,作为字符串的间隔符处理,倒序后
文章浏览阅读5w次,点赞36次,收藏138次。ArrayAdapter数组适配器用于绑定格式单一的数据,数据源可以是集合或者数组列表视图(ListView)以垂直的形式列出需要显示的列表项。实现过程:新建适配器->添加数据源到适配器->视图加载适配器第一种:直接用ListView组件创建列表每一行只有一行文字效果如图:activity_list布局:<?xml version="1.0" e..._arrayadapter
文章浏览阅读43次。近日,水滴直播平台登上了舆论的风口浪尖。有人认为水滴直播涉嫌侵犯隐私,但也有人表示这种互联网新生事物可以有效规避很多风险,值得鼓励,不应一棒子打死。记者采访时发现,很多商家、创业者对于水滴直播纷纷表示支持,并直言水滴直播为他们的经营带来了很大帮助。 邹志泉在北京丰台区经营着一家批发厂家直销男女内衣裤的店铺,平时就打开水滴直播,分享他在店铺的经营画面。面对水滴直播涉及隐私的提问,邹志泉明确表...
文章浏览阅读67次。springboot基于SpringBoot的电影社区网站。springboot基于springboot食品销售网站。ssm基于微信平台的校园汉服租赁系统的设计与实现。ssm基于SSM高校教师个人主页网站的设计与实现。ssm基于SSM框架的在线健康系统设计与实现。ssm基于HTML的武昌理工学院二手交易网站。ssm基于JavaEE的网上图书分享系统。ssm基于Javaee的项目任务跟踪系统。
文章浏览阅读61次。负载均衡是指将客户端的请求分发到多个后端服务器,以平衡服务器的负载。反向代理是指将客户端的请求转发到后端服务器,并将响应返回给客户端。通过配置反向代理,Nginx将转发所有来自客户端的请求到后端服务器,并将响应返回给客户端。通过这样的配置,Nginx将根据请求的URL路径选择是将请求转发到后端服务器还是直接返回静态资源文件。通过配置负载均衡,Nginx将按照指定的策略将客户端的请求分发到后端服务器上,从而实现负载均衡。配置反向代理:编辑Nginx配置文件(通常是nginx.conf),在。_php动静分离
文章浏览阅读9.5k次,点赞3次,收藏18次。(一) 语义标签(二)增强型表单(三)视频和音频(四)Canvas绘图(五)SVG绘图(六)地理定位(七)拖放API(八) WebWorker(九) WebStorage(十)Web..._谈谈html5的一些新特性