由不同状态下执行命令失败引发的思考

由不同状态下执行命令失败引发的思考

一、背景
开始想写这块内容,是由于我在调试过程中,遇见的一个神奇的问题。一开始,在电脑本地通过python调用shell命令执行Java程序,可以执行通过,在Linux上直接执行Java命令也可以执行通过。但是,将程序上传到Linux服务器上,执行失败了,提示是找不到Java命令。这是什么东西?最终虽然通过直接指定命令地址的方式,解决了这个问题,但原因一直不得而知。下面,是对这一问题的解答。

二、原因
在真正明白原因之前,我做了很多尝试。最初,我以为是supervisor托管的原因,所以我通过命令的方式,将服务直接启动,但依旧会提示找不到Java命令。因此,肯定不是因为supervisor的原因导致的。我切换了用户,试图以这种方式解决这个问题,但还是失败了。
程序执行Java命令提示失败,实质是因为用户态去执行了一个自身没有权限的获取到的内容,导致了执行失败。程序部署到Linux服务器上,通过python命令启动服务并完成后续的一系列操作,实际启用写入到用户态地址空间的是python环境变量。而在python环境变量里,并且没有告诉系统你要去执行外部命令,便直接执行Java命令,失败是很正常的事情。
那么,什么是用户态呢?
Linux系统架构有两种形态,分别是用户态和内核态。用户态是应用程序的活动空间,用户在Linux系统进行操作,执行程序命令等,都是在用户态开始。处于系统的最顶层。内核态主要是对Linux系统的资源进行分配。处于系统的底层。
为了避免资源的过度使用,以及约束用户行为。Linux不支持用户直接使用系统资源,只有内核态才有对系统资源的支配权,因此,处于用户态的用户在运行命令时,必须借由一种通信方式-系统调用,才能完成从用户态切换到内核态,从而完成命令的执行。所以,进行Linux系统调用的流程,是先用户态执行程序,遇到没有权限的内容,使用系统调用的方式,调用系统资源从而将程序执行切换到了内核态执行。
图片是网上找的,画的很到位
三、解决
知道了原因,解决这个问题就相对简单了。一种是告诉系统,你要调用外部命令,通过系统来调用。还有一种是直接定义你要调用的命令的地址,这样就相当于不需要系统加载命令的环境变量到用户态地址空间。下面,是对这两种方法详细的做法描述。

1、环境变量实质是为命令的地址取一个别名,用户在调用的时候可以更方便的进行调用。因此,在执行Java命令的时候,可以将Java直接写为Java命令的地址,这样,执行的时候就可以执行成功。
通过which+命令名称的形式,就可以获取到此命令的地址。在调用命令里,比如java -version 就可以切换为/usr/local/jdk/jdk1.8.0_45/bin/java -version的形式,两者是等价的。
2、使用系统调用的形式,调用Java命令,也可执行成功.例如,subprocess提供了call()用于调用外部命令。通过call()方法,就可以起到系统调用Java命令的作用,因此,在执行的时候,可以执行成功。
在这里插入图片描述
四、总结
当你碰见一个坑的时候,你要相信,这只是你会碰见的无数的坑中的其中一个,而你要做的,就是解决它。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值