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批处理脚本形式

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

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

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

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

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

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

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

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

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

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

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

  1. # coding=utf-8
  2. import os
  3. import tempfile
  4. # 将top.sh的Shell脚本copy过来,作为字符串变量
  5. top_sh = '''#!/bin/sh
  6. while true
  7. do
  8. top -n 1 >> /sdcard/top.log
  9. echo -e "$(date +%Y-%m-%d_%H:%M:%S)" >> /sdcard/top.log
  10. sleep 3
  11. done
  12. '''
  13. class ShellGeneratorAndRuner():
  14. '''Generate shell and push into android and run it'''
  15. def __init__(self, shell_script, push_path):
  16. self.script_text = shell_script
  17. self.push_path = push_path
  18. self.signal = None
  19. self.temp_file = None
  20. def generate_shell(self):
  21. print("正在生产Shell脚本的临时文件......")
  22. self.signal, self.temp_file = tempfile.mkstemp()
  23. with open(self.temp_file, 'w+', newline="\n") as hf: # 将支付按此转成Shell脚本,重点注意换行符"\n"
  24. for line in self.temp_file:
  25. hf.write(line)
  26. def push_run_shell(self):
  27. os.system("adb root") #必要的root
  28. os.system("adb remount")
  29. os.system("adb wait-for-device")
  30. os.system("adb push %s %s" % (self.temp_file, self.push_path)) # 推top.sh脚本到终端设备
  31. os.system("adb shell chmod 777 %s" % self.push_path) # 赋值777
  32. os.popen("adb shell nohup sh %s &" % self.push_path) # 独立后台无干扰执行,popen不阻塞
  33. print("%s 脚本后台无干扰运行中......"%self.push_path)
  34. def clear_tempfile(self):
  35. os.close(self.signal)
  36. os.remove(self.temp_file)
  37. if __name__ == '__main__':
  38. s_obj = ShellGeneratorAndRuner(top_sh, "/sdcard/top.sh")
  39. s_obj.generate_shell()
  40. s_obj.push_run_shell()
  41. s_obj.clear_tempfile()
  42. 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. On Fixed-Point Implementation of Log-MPA for SCMA Signals

    目录 论文来源 摘要 基本概念 1.SCMA 2.SCMA编码器 研究内容 1.基于Log-MPA的SCMA解码器实现过程 论文创新点 借鉴之处 论文来源 本论文来自于IEEE WIRELESS CO ...

  2. ORACLE数据库实现主键自增

    ORACLE数据库是甲骨文公司的一款关系数据库管理系统. 实现主键自动增长需要四个步骤: 去看 创建表格 去看 创建自增序列 去看 创建触发器 去看 插入测试 1.创建表格(必须有主键) -- 创建学 ...

  3. JZOJ 5286. 【NOIP2017提高A组模拟8.16】花花的森林 (Standard IO)

    5286. [NOIP2017提高A组模拟8.16]花花的森林 (Standard IO) Time Limits: 1000 ms Memory Limits: 131072 KB Descript ...

  4. disruptor 多生产者多消费者实战 四

    一.创建event类 Order public class Order { private String id; private String name; private double price; ...

  5. vuex和localStorage,全局变量的区别

    vuex是状态管理,是为了解决跨组件之间数据共享问题的,一个组件的数据变化会映射到使用这个数据的其他组件当中.如果刷新页面,之前存储的vuex数据全部都会被初始化掉. localStorage是H5提 ...

  6. Oracle批量插入有日期类型数据

    例如现在有张表 id(number) startTime(date) name(varchar2) 1 2017-08-13  zhangsan 2 2017-08-14  zhangsan 需要批量 ...

  7. optimizing Wi-Fi solution for International School

    https://aweisoft.azurewebsites.net/Knowledge/Cisco/OptimizeWiFi/OptimizeWiFi.aspx Connect me on Link ...

  8. Go语言转义字符

    \a 匹配响铃符 (相当于 \x07) 注意:正则表达式中不能使用 \b 匹配退格符,因为 \b 被用来匹配单词边界, 可以使用 \x08 表示退格符. \f 匹配换页符 (相当于 \x0C) \t ...

  9. Java集合02——三分钟了解你必须掌握的两个Set

    上一篇文章我们说到了 List ,本章开始,我们将继续讲解Set相关的知识.关注公众号「Java面典」了解更多 Java 知识点. Set 是一个无重复对象的集合类.值的重复与否是根据对象的 hash ...

  10. django中ORM中锁和事务

    一 锁 行级锁 select_for_update(nowait=False, skip_locked=False) #注意必须用在事务里面,至于如何开启事务,我们看下面的事务一节. 返回一个锁住行直 ...