python adb shell_《自拍教程52》Python_adb运行Shell脚本

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

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

Shell脚本的执行的优势:

快捷高效,Shell脚本是Linux终端都支持的。

由于执行及测试结果都在Linux终端内部存储,不会出现因为反复通过USB与Windows电脑进行输入输出导致的Android系统的I/O CPU消耗过大。

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

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

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

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

Shell脚本的三种运行方式

具体命令

具体效果

adb shell sh top.sh (低端)

执行在前台,即“阻塞”在前台运行,会让你在这个界面等着。

拔掉USB线后,Shell脚本自动停止执行

adb shell sh top.sh &(中端)

执行在后台,即“不阻塞”,让后台执行了,不需要你等着执行完。

拔掉USB线后,Shell脚本自动停止执行

adb shell nohup sh top.sh &(高端)

独立执行在后台,执行后,即使你拔掉USB线,Shell脚本依旧后台运行。

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

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

融合方式

具体效果

显露式(低端)

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文件等等),

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值