Android作为一款Linux终端,肯定是支持.sh后缀的Shell脚本的运行的,

有时候测试环境准备或者长时间截取复杂的日志等,开发会给到一些Shell脚本。

Shell脚本的执行的优势:

  1. 快捷高效,Shell脚本是Linux终端都支持的。
  2. 由于执行及测试结果都在Linux终端内部存储,不会出现因为反复通过USB与Windows电脑进行输入输出导致的Android系统的I/O CPU消耗过大。

如何通过Python来运行Shell脚本呢?

何为高端地用Python运行Shell脚本,这里边的学问可不小,

以下案例,我们写了一个top.sh脚本, 用于持续截取系统各App的cpu占用率情况。

持续截取cpu占用率数据,也是App性能测试(资源消耗)的常用测试方法。

Shell脚本的三种运行方式

table th:first-of-type {
width: 100px;
}

具体命令 具体效果
adb shell sh top.sh (低端) 执行在前台,即“阻塞”在前台运行,会让你在这个界面等着。
拔掉USB线后,Shell脚本自动停止执行
adb shell sh top.sh &(中端) 执行在后台,即“不阻塞”,让后台执行了,不需要你等着执行完。
拔掉USB线后,Shell脚本自动停止执行
adb shell nohup sh top.sh &(高端) 独立执行在后台,执行后,即使你拔掉USB线,Shell脚本依旧后台运行。

本案例用第三种高端方式来实现

Shell脚本与Python文件相互存在的两种方式

table th:first-of-type {
width: 100px;
}

融合方式 具体效果
显露式(低端) top.sh脚本和Python脚本都是独立的文件,top.sh显露在外
---run_top_sh.py
---top.sh
隐藏式(高端) 将top.sh以文本的形式隐藏在Python代码中
---run_top_sh.py

显露式的方法,肯定是adb push top.sh /sdcard/top.sh,

本案例脚本用第二种隐藏式高端方式来实现, 具体如何实现呢?

准备阶段

第1步: 将Shell脚本以字符串变量的形式存放于Python代码块里

第2步: 将Shell脚本写入一个临时文件(注意Shell脚本是需要运行在Linux,Linux的行尾符是\n)

第3步: 将以上临时文件adb push 到/sdcard/cpu.sh

第4步: 用adb shell nohup sh /sdcard/cpu.sh & 的方式实现长时间截取,即使USB不小心掉了,也不影响Shell脚本继续在后执行截取top。

Python批处理脚本形式

记住批处理脚本的精髓:批量顺序执行语句

# coding=utf-8

import os
import tempfile # 将top.sh的Shell脚本copy过来,作为字符串变量
top_sh = '''#!/bin/sh
while true
do
top -n 1 >> /sdcard/top.log
echo -e "$(date +%Y-%m-%d_%H:%M:%S)" >> /sdcard/top.log
sleep 3
done
''' print("正在生成Shell脚本的临时文件......")
signal, temp_file = tempfile.mkstemp() # 创建一个临时文件
with open(temp_file, 'w+', newline="\n") as hf: # 将支付按此转成Shell脚本,重点注意换行符"\n"
for line in top_sh:
hf.write(line) os.system("adb root") #必要的root
os.system("adb remount")
os.system("adb wait-for-device")
os.system("adb push %s /sdcard/top.sh" % temp_file) # 推top.sh脚本到终端设备
os.system("adb shell chmod 777 /sdcard/top.sh") # 赋值777
os.popen("adb shell nohup sh /sdcard/top.sh &") # 独立后台无干扰执行,popen不阻塞
print("/sdcard/top.sh 脚本后台无干扰运行中......") print("清除临时文件......")
os.close(signal) # 临时文件清理
os.remove(temp_file) # 临时文件清理 os.system("pause")
Python面向过程函数形式

面向过程函数的编程思维应该是这样的:

你需要多少个功能(函数),才能做成这个事。

最好把功能(函数)都尽量封装好,只暴露一定的参数接口即可。

import os
import tempfile # 将top.sh的Shell脚本copy过来,作为字符串变量
top_sh = '''#!/bin/sh
while true
do
top -n 1 >> /sdcard/top.log
echo -e "$(date +%Y-%m-%d_%H:%M:%S)" >> /sdcard/top.log
sleep 3
done
''' def generate_shell(shell_script):
print("正在生成Shell脚本的临时文件......")
signal, temp_file = tempfile.mkstemp() # 创建一个临时文件
with open(temp_file, 'w+', newline="\n") as hf: # 将支付按此转成Shell脚本,重点注意换行符"\n"
for line in shell_script:
hf.write(line)
return signal, temp_file def clear_tempfile(signal, temp_file):
print("清除临时文件......")
os.close(signal)
os.remove(temp_file) def push_run_shell(sh_file, push_path):
os.system("adb root") #必要的root
os.system("adb remount")
os.system("adb wait-for-device")
os.system("adb push %s %s" % (sh_file, push_path)) # 推top.sh脚本到终端设备
os.system("adb shell chmod 777 %s" % push_path) # 赋值777
os.popen("adb shell nohup sh %s &" % push_path) # 独立后台无干扰执行,popen不阻塞
print("%s 脚本后台无干扰运行中......"%push_path) signal, temp_file = generate_shell(top_sh)
push_run_shell(temp_file, "/sdcard/top.sh")
clear_tempfile(signal, temp_file) os.system("pause")
Python面向对象类形式

面向对象类的编程思维应该是这样的:

如果给你一个空白的世界,在这个世界里你需要哪些种类的事物,

这些种类的事物都具备哪些共有的属性与方法,

这些种类(类)的事物(对象),和其他种类(其他类)的事物(其他对象)有什么关系。

尽量把这些类封装好,只暴露对外的属性(变量)和方法(函数)即可。

# coding=utf-8

import os
import tempfile # 将top.sh的Shell脚本copy过来,作为字符串变量
top_sh = '''#!/bin/sh
while true
do
top -n 1 >> /sdcard/top.log
echo -e "$(date +%Y-%m-%d_%H:%M:%S)" >> /sdcard/top.log
sleep 3
done
''' class ShellGeneratorAndRuner():
'''Generate shell and push into android and run it''' def __init__(self, shell_script, push_path):
self.script_text = shell_script
self.push_path = push_path
self.signal = None
self.temp_file = None def generate_shell(self):
print("正在生产Shell脚本的临时文件......")
self.signal, self.temp_file = tempfile.mkstemp()
with open(self.temp_file, 'w+', newline="\n") as hf: # 将支付按此转成Shell脚本,重点注意换行符"\n"
for line in self.temp_file:
hf.write(line) def push_run_shell(self):
os.system("adb root") #必要的root
os.system("adb remount")
os.system("adb wait-for-device")
os.system("adb push %s %s" % (self.temp_file, self.push_path)) # 推top.sh脚本到终端设备
os.system("adb shell chmod 777 %s" % self.push_path) # 赋值777
os.popen("adb shell nohup sh %s &" % self.push_path) # 独立后台无干扰执行,popen不阻塞
print("%s 脚本后台无干扰运行中......"%self.push_path) def clear_tempfile(self):
os.close(self.signal)
os.remove(self.temp_file) if __name__ == '__main__':
s_obj = ShellGeneratorAndRuner(top_sh, "/sdcard/top.sh")
s_obj.generate_shell()
s_obj.push_run_shell()
s_obj.clear_tempfile() os.system("pause")
运行方式与效果

确保Android设备通过USB线与电脑连接了,adb设备有效连接,

以上代码的3种实现形式都可以直接运行,比如保存为run_top_sh.py并放在桌面,

建议python run_top_sh.py运行,当然也可以双击运行。

运行效果如下:

其中C:\Users\ADMINI~1\AppData\Local\Temp\tmp5way7qgx这个就是生成的临时文件,

由于一般用户不会涉及到以上临时文件,所以可以实现“无感”地生成Shell脚本。

为什么鼓励用隐藏式来隐藏Shell脚本到代码里去,

因为比如后续你写了一个Python工具,这个工具用py2exe编译时,

py2exe只能编译打包.py的文件成.exe, 其他的任何非.py的文件无法打包进来,

如果你发布给别人用的时候,也就一个.exe,

大家就觉得你的工具做的比较好,集成的比较好。

相反地,如果你的.exe工具再带一堆的Shell脚本,或者其他资源文件,配置文件等,

则相对而言没那么易用,比如容易动不动出现配套文件找不到,

或者被用户随意篡改导致程序无法正常运行,也无法显示你的作品的牛逼。。。

不仅仅是Shell脚本,任何文本形式的文件(配置文件,脚本文件,其他log文件等等),

都可以考虑用以上这种方法附带。。。

更多更好的原创文章,请访问官方网站:www.zipython.com

自拍教程(自动化测试Python教程,武散人编著)

原文链接:https://www.zipython.com/#/detail?id=97cbb5fd8dcf4c40a549e565ca0b6f6a

也可关注“武散人”微信订阅号,随时接受文章推送。

《自拍教程52》Python_adb运行Shell脚本的更多相关文章

  1. mac终端下运行shell脚本

    最近公司要弄关于IOS下自动化打包的东西,研究了用命令行的形式来代替手工的方式来处理.即: 用xcodebuild 和xcrun  语法来进行脚本实现.    但由于语法的结构够了,另一个问题产生了, ...

  2. Shell教程1​-第一个Shell脚本

    打开文本编辑器,新建一个文件,扩展名为sh(sh代表shell),扩展名并不影响脚本执行,见名知意就好,如果你用php写shell 脚本,扩展名就用php好了.输入一些代码: #!/bin/bash ...

  3. 【转】shell 教程——05 第一个Shell脚本

    打开文本编辑器,新建一个文件,扩展名为sh(sh代表shell),扩展名并不影响脚本执行,见名知意就好,如果你用php写shell 脚本,扩展名就用php好了. 输入一些代码: #!/bin/bash ...

  4. 运行shell脚本时报错"[[ : not found"解决方法

    问题描述 在运行shell脚本时报错,命令为: sh test.sh 报错如图: 脚本代码如下: #!/bin/bash # file:test.sh # author:13 # date:2017- ...

  5. Shell教程 之第一个shell脚本

    1.第一个shell脚本 打开文本编辑器(可以使用 vi/vim 命令来创建文件),新建一个文件 test.sh,扩展名为 sh(sh代表shell),扩展名并不影响脚本执行 输入一些代码 #!/bi ...

  6. IDEA中编写脚本并运行shell脚本

    IDEA中编写脚本并运行shell脚本     来自 <https://blog.csdn.net/u012443641/article/details/81295999>

  7. 在windows下使用shell,运行shell脚本

    在Windows操作系统下运行Shell脚本,缺少的只是一个Git软件.其下载路径为Git - Downloading Package. 安装之后,将安装路径下的bin文件夹的路径作为环境变量.于是我 ...

  8. Linux运维初级教程(一)Shell脚本

    序,掌握shell脚本是linux运维工程师的最基础技能. 一.脚本语言 与高级语言不通,脚本语言运行时需要调用相应的解释器来翻译脚本中的内容. 常见的脚本语言有Shell脚本.Python脚本.ph ...

  9. 创建和运行shell脚本程序

    转载请标明http://www.cnblogs.com/winifred-tang94/ 要创建一个shell脚本程序,首先新建一个文本文件,然后在这个文本文件中按照shell编程规则输入shell命 ...

随机推荐

  1. python爬虫-scrapy日志

    1.scrapy日志介绍 Scrapy的日志系统是实现了对python内置的日志的封装 scrapy也使用python日志级别分类 logging.CRITICAL logging.ERROE log ...

  2. Java入门教程十一(异常处理)

    在程序设计和运行的过程中,发生错误是不可避免的.尽管 Java 语言的设计从根本上提供了便于写出整洁.安全代码的方法,并且程序员也尽量地减少错误的产生,但是使程序被迫停止的错误的存在仍然不可避免.为此 ...

  3. 彻底消灭if-else嵌套

    一.背景 1.1 反面教材 不知大家有没遇到过像横放着的金字塔一样的if-else嵌套: if (true) { if (true) { if (true) { if (true) { if (tru ...

  4. 程序小白如何快速开发OA办公系统

    对于企业开发oa办公系统,成本高,周期长.有些企业花高价购买,购买后受制于软件商,很多功能只能按原来设计需求走,无法升级或者升级慢.这些由于软件商的开发效率低难以及时地响应企业的需求变化,所以就有可能 ...

  5. Murata村田研发向左,制造向右

    前言:Murata村田自1944 年在日本京都创立,是陶瓷无源电子元件.无线连接模块和电源转换技术产品设计和制造领域的全球领导者. Murata 一直在为社会的进步和电子行业的革命贡献自己的力量. 在 ...

  6. metrics模块

    class sklearn.metrics 方法 1.分类问题的度量 metrics.accuracy_score metrics.auc metrics.f1_score metrics.preci ...

  7. Service Mesh - gRPC 本地联调远程服务

    Description Service Mesh 架构下,服务间调用会通过服务名(Service Name)互相调用,比如在 Kubernetes .Docker Swarm 集群中,服务 IP 均由 ...

  8. 一起了解 .Net Foundation 项目 No.14

    .Net 基金会中包含有很多优秀的项目,今天就和笔者一起了解一下其中的一些优秀作品吧. 中文介绍 中文介绍内容翻译自英文介绍,主要采用意译.如与原文存在出入,请以原文为准. .NET Core .NE ...

  9. 304 Not Modified

    304 Not Modified,不是服务器发出的错误,是服务器所承载的业务系统在开发时为了节省带宽和提升浏览器的体验,对GET/js,css,image等执行了缓存机制.客户端第一次对服务器发出GE ...

  10. 28 复杂的使用Specification查询

    /** * Specification的多表查询 */ @Test public void testFind() { Specification<LinkMan> spec = new S ...