Shell学习5_ expect spawn not found报错解决

本文详细解析了在Linux环境下使用expect脚本进行自动化交互时,遇到的spawn not found错误的原因及解决方案。强调了脚本执行方式对错误的影响,并提供了正确的脚本运行方法。

安装expect 执行以下命令

sudo apt-get install tcl tk expect

在使用expect 写自动交互功能时 遇到问题

automate_expect.sh

#! /usr/bin/expect

spawn ./interactive.sh

expect "Enter number:"

send "1\n"

expect eof

 

然后在命令行输入

sh automate_expect.sh

 

既然出现 spawn not  found 错误

 

一直出现这个错误,基本上都是出学者

原来linux 执行sh脚本有两种方式,一种时将脚本作为sh 的命令行参数,另一种时将脚本作为具有执行权限的可执行脚本

将脚本作为sh 的命令行参数运行的方式如下

sh script.sh 或 sh /home/path/script.sh

将脚本作为具有执行权限的可执行脚本运行方式如下

先然脚本文件具有可执行权限,执行下面代码

chmod a+x  script.sh 或chmod 755 script.sh

执行脚本

./script.sh 或/home/path/script.sh

 

而作为sh 命令行参数来运行。那么脚本的#! 的一行就会失效

所以才会出现spawn not found 错误,所有上面的automate_expect.sh 脚本必须用以前命令运行

./automate_expect.sh


————————————————
版权声明:本文为优快云博主「cbluehehe」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.youkuaiyun.com/chinabluexfw/article/details/7461944

operator.py: import re import time import pexpect import sys import os import subprocess from libs.printer import print_passed, print_failed, print_info, print_error from libs.args_parser import get_args from libs.serial_client import SerialClient from libs.operation import * from libs.relays_client import * def check_AVC(): print_info('Check AVC') adb = AdbOperator() sys = SysOperation(timeout=30) adb.__enter__() ret = adb.send_cmd_result('dmesg |grep avc') if 'avc:' in ret: print_error("Matched avc Log") adb.send_cmd_and_expect('reboot -f',expect_str='Rebooting') print_info('time sleep 30s') time.sleep(30)#等待重启 ret = sys.execute_cmd(f'adb -s {adb.device_id} wait-for-device devices') if ret == "timeout" : return -99 return -1 def get_calling_script(): calling_scripts = [] def find_caller(frame): nonlocal calling_scripts if frame is None or '__main__' in frame.f_globals: return caller_path = frame.f_code.co_filename calling_scripts.append(caller_path) find_caller(frame.f_back) find_caller(sys._getframe()) return calling_scripts[-1] if len(calling_scripts) > 0 else '' class AdbOperator: def __init__(self, device=None, passwd=None,timeout=5, print_result=True, exec_dir='/oemdata/bin', device_type='AN758', log_number=0, log_path_array=None): self.args = get_args() self.timeout = timeout self.log_str = '' self.status = 0 self.print_result = print_result # 是否打印结果(passed/failed) self.need_password = False if device == None: self.device_id = self.args.serial else: self.device_id = device if passwd == None: self.passwd = self.args.passwd else: self.passwd = passwd self.exec_dir = f"{self.args.exec_dir}" self.exec_dir = exec_dir self.version = self.args.version self.phone = self.args.phone self.puk = self.args.puk self.pin = self.args.pin self.operator_id = self.args.operator self.platform = self.args.platform self.device_type = self.args.project self.script_name = os.path.splitext(os.path.basename(get_calling_script()))[0] self.start_time = time.strftime("%Y%m%d%H%M%S") #self.log_number = log_number self.log_path_array = log_path_array self.id_name_list = [] def copy_log(self): # 获取当前脚本所在的目录 script_dir = os.path.dirname(os.path.abspath(__file__)) dest_dir = script_dir + '/../log/' + self.script_name + '_' + self.device_id + '_' + self.start_time os.makedirs(dest_dir, exist_ok=True) self.get_root_permission() self.enter_to_module() self.send_cmd_and_expect('fibo_trustzone_example -l', expect_str='tz_log', timeout=30) time.sleep(2) #os.system(f'echo {self.passwd} | adb -s {self.device_id} pull /data/vendor/telsdk/tel.log {dest_dir}') os.system(f'echo {self.passwd} | adb -s {self.device_id} pull /tmp/tz_log/ {dest_dir}') #os.system(f'echo {self.passwd} | adb -s {self.device_id} shell dmesg > {dest_dir}/dmesg.log') os.system(f'echo {self.passwd} | adb -s {self.device_id} pull /etc/misc/wifi {dest_dir}') os.system(f'cp {script_dir}/../log/serial_log {dest_dir}') if self.log_path_array is not None: for log_path in self.log_path_array: os.system(f'echo {self.passwd} | adb -s {self.device_id} pull {log_path} {dest_dir}') # 2023-03-14 add by: shi_dian # 进入adb shell时,可自动识别是否需要root密码 def enter_to_module(self,passwd=None): """进入模组""" print_info(f'adb -s {self.device_id} wait-for-device shell') p = pexpect.spawn( 'adb', ['-s', self.device_id, 'wait-for-device', 'shell'], encoding='utf-8', timeout=self.timeout, codec_errors='replace' ) p.logfile_read = sys.stdout self.p = p expect_ret = p.expect(['Enter root Passwd:','Enter user Passwd:' ,pexpect.EOF, pexpect.TIMEOUT], timeout=3) #exec_result += str(p.before) #if p.after is not None and type(p.after) is str: # exec_result += str(p.after) if expect_ret == 0 or expect_ret == 1: self.need_password = True time.sleep(1) # 需要输入root时,输入root密码 #print_info(f'input root passwd={self.passwd}') if passwd: p.sendline(passwd) else: p.sendline(self.passwd) ret = p.expect(['\#', '\$' ,pexpect.EOF, pexpect.TIMEOUT], timeout=10) if ret == 3: relays = RelaysClient() print_info('######################################') print_info('ERROR: Not Find USB Go To Hard Restart') print_info('######################################') self.set_status_failed() relays.__enter__() relays.set_reset_connect_once() relays.__exit__() try: self.p.expect(pexpect.TIMEOUT, timeout=1) except Exception as e: print_error(f'Exception={e}') pass #exec_result += str(p.before) #self.log_str += exec_result #print(self.log_str) #print(f'platform_name={self.platform}') #if self.platform in ['SA6125']: # self.send_cmd_and_return('export LD_LIBRARY_PATH=/tbox/umdp/lib') # self.send_cmd_and_return("export LD_LIBRARY_PATH='/tbox/umdp/lib:/vendor/lib64:/system/lib64'") # self.send_cmd_and_return('export LD_LIBRARY_PATH=\'/tbox/umdp/lib:/vendor/lib64:/system/lib64\'', # 'export LD_LIBRARY_PATH.*system/lib64[^\n]*', timeout=10) return p def open_test(self, test_name, parse_menu=False, exp_str=None, timeout=None,test_dir=None): """打开test demo""" exec_test_dir = self.exec_dir if test_dir: exec_test_dir = test_dir #print_info(f'{test_name} run test case start') if exp_str is None: ret = self.send_cmd_and_expect(f'.{exec_test_dir}/{test_name}') else: ret = self.send_cmd_and_expect(f'.{exec_test_dir}/{test_name}', expect_str=f'{exp_str}', timeout=timeout) time.sleep(2) if parse_menu: try: self.p.expect(pexpect.TIMEOUT, timeout=2) except Exception as e: print(f'Exception={e}') finally: log = '' if self.p.before is not None: log = self.p.before.strip() temp_cmd_list = log.splitlines() id_name_list = [] for line_str in temp_cmd_list: if re.match('\\d*:.', line_str): temp = line_str.replace('\t', '').replace('\n', '').replace('\r', '') temp_list = temp.split(':') obj_dict = dict() obj_dict['id'] = temp_list[0] obj_dict['name'] = temp_list[1] id_name_list.append(obj_dict) self.id_name_list = id_name_list #print('------------- menu item ------------') # print(self.id_name_list) # for item in self.id_name_list: # print(item) return ret def open_tz_test(self, test_name, parse_menu=False, exp_str=None, timeout=None): """打开test demo""" exec_test_dir = self.exec_dir #print_info(f'{test_name} run test case start') if exp_str is None: ret = self.send_cmd_and_expect(f'./{test_name}') else: ret = self.send_cmd_and_expect(f'./{test_name}', expect_str=f'{exp_str}', timeout=timeout) time.sleep(2) if parse_menu: try: self.p.expect(pexpect.TIMEOUT, timeout=2) except Exception as e: print(f'Exception={e}') finally: log = '' if self.p.before is not None: log = self.p.before.strip() temp_cmd_list = log.splitlines() id_name_list = [] for line_str in temp_cmd_list: if re.match('\\d*:.', line_str): temp = line_str.replace('\t', '').replace('\n', '').replace('\r', '') temp_list = temp.split(':') obj_dict = dict() obj_dict['id'] = temp_list[0] obj_dict['name'] = temp_list[1] id_name_list.append(obj_dict) self.id_name_list = id_name_list #print('------------- menu item ------------') # print(self.id_name_list) # for item in self.id_name_list: # print(item) return ret def get_id_by_name(self, name): for temp in self.id_name_list: if temp['name'].lower() == name.lower(): # print(f'\n\n{temp}', end='') return temp['id'] print_error(f'----------------------- get_id_by_name() 没有找到选项: name={name} -------------------') return str(-1) def send_cmd_and_expect(self, cmd=None, expect_str=None, timeout=None): """发送命令并判断期望的字符串是否出现""" if cmd != None: self.p.sendline(cmd) if expect_str: # 如果没有匹配到任何字符则抛出异常 if timeout is None: nowstatus = self.p.expect([expect_str, pexpect.EOF, pexpect.TIMEOUT]) else: nowstatus = self.p.expect([expect_str, pexpect.EOF, pexpect.TIMEOUT], timeout=timeout) if nowstatus != 0: self.status = nowstatus print_error(f'not match:{expect_str} nowstatus:{nowstatus}') #else: # print(f'match {expect_str}') #self.print_log() #print(f'--- current status: {nowstatus} ---') return nowstatus time.sleep(0.5) return 0 def send_cmd_and_return(self, cmd = None, expect_str=None, timeout=None): """发送命令并查找返回匹配的字符串,未匹配到返回None""" if cmd != None: self.p.sendline(cmd) if expect_str: if timeout is None: nowstatus = self.p.expect([expect_str, pexpect.EOF, pexpect.TIMEOUT]) else: nowstatus = self.p.expect([expect_str, pexpect.EOF, pexpect.TIMEOUT], timeout=timeout) #self.print_log() #print(f'--- current status: {nowstatus} ---') if nowstatus == 0: # 匹配到 print_info(f'match:{expect_str}') return self.p.after else: return None def send_cmd_and_return_stdout(self, cmd, timeout=20): """发送命令并返回输出的字符串""" self.p.expect(r".*", timeout=1) # 非阻塞读取所有已有数据 self.p.sendline(cmd) self.p.expect([pexpect.EOF, pexpect.TIMEOUT], timeout=timeout) stdout = self.p.before return stdout def send_cmd_result(self, cmd): try: """发送命令并查找返回结果""" res = self.p.sendline(cmd) self.p.expect('sftp>') except Exception as e: print(f'Exception={e.msg}') finally: if self.p.before is None: return '' return self.p.before.strip() def send_cmd_exp_list(self, cmd_exp_list, sleep_time=2): """执行多条命令和期望值来判断返回的status是否为0,为0则成功,否则失败""" for cmd, exp_str in cmd_exp_list: self.status = self.send_cmd_and_expect(cmd, expect_str=exp_str) if self.status != 0: break time.sleep(sleep_time) return self.status def send_clear_expect_data(self): #清空expect后的数据,保证下次期待值为输入指令后的输出 self.p.expect(r".*", timeout=1) # 非阻塞读取所有已有数据 def exit_test(self, cmd='-1'): """退出测试demo,发送-1""" self.send_cmd_result(cmd) def print_log(self): """打印当前信息""" if isinstance(self.p.after, str): # 匹配到 expect_log_str = self.p.before + self.p.after self.log_str += expect_log_str print(expect_log_str) else: print_info(f"not find expect info") # Add by hla 2022/6/20 print(self.p.before) # Add by hla 2022/6/20 print(self.p.after) # <class 'pexpect.exceptions.TIMEOUT'> def get_log_str(self): """获取日志信息""" # remaining_log = self.p.read() # if isinstance(remaining_log, str): # print(remaining_log) # self.log_str += remaining_log # Modified by HLA,2022-6-27,self.p.read()会遇到读取异常的场景,添加异常处理 try: remaining_log = self.p.read() if isinstance(remaining_log, str): print(remaining_log) self.log_str += remaining_log except: remaining_log = 'get_log_str error' print(remaining_log) self.log_str += remaining_log def check_status(self): """检查状态""" if self.status == 0: print_passed() else: print_failed() def is_fail(self): if self.status == 0: return False else: return True def set_status(self, status): self.status = status def get_status(self): return self.status def set_status_failed(self): print_error('Set Test Result To Fail') self.status = -100 def is_need_password(self): return self.need_password def get_root_permission(self,timeout=60,passwd=None): """获取root权限""" count = 0 while count < 2: ''' if self.device_type == 'AN960': print_info(f'adb -s {self.device_id} wait-for-device root') p = pexpect.spawn( 'adb', ['-s', self.device_id, 'wait-for-device', 'root'], encoding='utf-8', timeout=5, ) else: print_info(f'adb -s {self.device_id} wait-for-device shell root') p = pexpect.spawn( 'adb', ['-s', self.device_id, 'wait-for-device', 'shell','root'], encoding='utf-8', timeout=5, ) ''' print_info(f'adb -s {self.device_id} wait-for-device shell root') p = pexpect.spawn( 'adb', ['-s', self.device_id, 'wait-for-device', 'shell','root'], encoding='utf-8', timeout=5, ) p.logfile_read = sys.stdout time.sleep(0.1) ret = p.expect(['adb root success', 'Enter root Passwd:', 'adb has running as root', 'adbd is already running as root', 'adb is already running as root', 'root: not found','restarting adbd as root', pexpect.EOF, pexpect.TIMEOUT], timeout=timeout) if ret == 0: print_info('adb root success, current device dose not use passwd.') time.sleep(1) # wait 1s for root permission to take effect. count = 2 elif ret == 1: if passwd: p.sendline(passwd) else: p.sendline(self.passwd) time.sleep(0.1) passwd_status = p.expect(['adb root success', 'Error root Passwd']) if passwd_status == 0: print_info('get root permission success.') time.sleep(1) else: print_error('get root permission failed.') count = 2 elif ret == 6: print_info('try again because eof.') count = count + 1 elif ret == 7: print_info('try again because timeout.') count = count + 1 else: #print_info(f'ret is {ret}.') count = 2 def get_oemdata_permission(self): """get permission of /oemdata.""" #print_info('mount -T . -o remount,exec /oemdata') #cmd = './mnt/sdcard/run_rild.sh' cmd = 'mount -T . -o remount,exec /oemdata' self.send_cmd_and_expect(cmd, '[#$]') # self.send_cmd_and_expect(cmd, r"\[PEXPECT\][\$\#] ") # PS1='[PEXPECT]\$ ' def run_telsdk_subsystem(self): if 0 != self.send_cmd_and_expect('ps -ef | grep rild',expect_str='rild -l'): self.send_cmd_and_expect('./mnt/sdcard/run_rild.sh') time.sleep(2) # def set_device_sleep(self): # gpio = SerialClient(serialType = SERIAL_TYPE_CONTROL) # gpio.__enter__() # self.open_test('telux_power_test_app -s') # time.sleep(1) # gpio.set_usb_line_disconnect() # gpio.__exit__() # def set_device_shutdown(self): # gpio = SerialClient(serialType = SERIAL_TYPE_CONTROL) # gpio.__enter__() # self.open_test('telux_power_test_app -p') # time.sleep(2) # gpio.set_power_line_disconnect() # gpio.__exit__() def __enter__(self): self.get_root_permission() self.p = self.enter_to_module() time_result = subprocess.run(['date', '-u', '+%Y-%m-%d %H:%M:%S'], capture_output=True, text=True) self.send_cmd_and_expect(f'date -s "{time_result.stdout.strip()}"') #self.get_oemdata_permission() #if self.device_type != 'AN960': # self.run_telsdk_subsystem() return self def __exit__(self, exc_type=None, exc_val=None, exc_tb=None): """退出""" if exc_type: print('遇到异常了,异常信息为:', exc_type, exc_val, exc_tb) # print(f'### exit module {self.device_id} ###') # self.get_log_str() # if self.status != 0: # self.copy_log() if self.print_result: self.check_status() # return True # 抛出错误 # class NWOperator(AdbOperator): # def set_network(self, mode, nw_type=''): # print(f"set_network() mode={mode}, nw_type={nw_type}") # """注网""" # if mode in ['0x10', '0x40']: # self.check_ims_status() # self.open_test('nw_test') # # fibo_nw_client_init # self.send_cmd_and_expect('0', expect_str='ret\\s*[:=]\\s*0[^\n]*') # # fibo_nw_set_config # self.send_cmd_and_expect('1') # # please input mode config hex(0x01:CDMA; 0x02:EVDO; 0x04:GSM; 0x08:UMTS; 0X10:LTE; 0x20:TDSCDMA; 0x40:SA; 0x80:AUTO) # self.send_cmd_and_expect(mode) # # please input roaming pref(0:off 1:on) # self.send_cmd_and_expect('1', expect_str='ret\\s*[:=]\\s*0[^\n]*') # time.sleep(5) # for i in range(5): # status = self.send_cmd_and_return('7', f'radio_tech:\\s*{nw_type}[^\n]*', timeout=10) # if status != None: # break # self.exit_test() # if status != None: # print('### 注网成功 ###') # return 0 # else: # self.status = 2 # 标记用例失败 # print('### 注网失败 ###') # return 2 # def get_network(self): # """获取当前网络状态""" # self.open_test('at_test') # self.send_cmd_and_expect('AT+COPS?', 'COPS: 0,0,\".*?\",(\d+)') # nw_status = self.p.match.group(1) # print(f'### 当前网络状态码为{nw_status} ###') # self.exit_test() # return nw_status # def check_ims_status(self): # """ # 检测IMS是否被激活(二路获取到IP地址则为激活状态) # """ # print('### 正在检测ims是否被激活 ###') # self.open_test('nw_test') # self.send_cmd_and_expect('0') # fibo_nw_client_init # # self.send_cmd_and_expect('22', 'ims value:(\d)') # fibo_nw_get_ims # ims_status = self.send_cmd_and_return('22', 'ims value:(\d)') # # ims_status = self.p.match.group(1) # if ims_status == 'ims value:1': # print('### ims已被激活 ###') # else: # print('### 检测到ims尚未激活,正在重新激活 ###') # self.send_cmd_and_expect('23') # self.send_cmd_and_expect('1', 'fibo_nw_set_ims return:0') # print('### 成功激活ims ###') # self.exit_test() # def set_ims_status(self, status): # """ # 设置IMS状态(0-disable, 1-enable) # :param status: ims状态 # :return: # """ # self.open_test('nw_test') # self.send_cmd_and_expect('0') # fibo_nw_client_init # self.send_cmd_and_expect('23') # fibo_nw_client_init # self.send_cmd_and_expect(status) # self.send_cmd_and_expect('22', 'ims value:\d') # print(f'### 设置IMS成功,当前状态为{status} ###') # self.exit_test() # class VoiceOperator(AdbOperator): # def __init__(self, device_id, passwd, timeout=30, print_result=True,phone=None): # super().__init__(device_id, passwd, timeout, print_result,exec_dir='/usr/bin',device_type='') # self.phone = phone # def init_voice_client(self): # """初始化voice_client, 开启主动上报""" # print(f'### 正在初始化模组{self.device_id}的voice_test ###') # self.send_cmd_and_expect('0') # Fibo_VOICE_Client_Init # self.send_cmd_and_expect('12') # Fibo_VOICE_Call_AddStateHandle # self.send_cmd_and_expect('18') # fibo_voice_register_bitmask # self.send_cmd_and_expect('1') # bitmask mode 0x01 ->call event # def call(self): # """拨打电话""" # print(f'### 模组{self.device_id}拨打电话,号码为{self.phone} ###') # self.open_test('telsdk_console_app') # self.send_cmd_and_expect('2', expect_str='Dialer Menu') # self.send_cmd_and_expect('4 1') # self.send_cmd_and_expect('4 2') #hangup all Inprogress call # self.send_cmd_and_expect(f'1 {self.phone}', expect_str='makeCall response ErrorCode: 0') # phone number # self.send_cmd_and_expect('0', expect_str='Telematics SDK') #exit Data Menu # self.exit_test('0') # def answer(self): # """接听电话""" # self.open_test('telsdk_console_app') # self.send_cmd_and_expect('2', expect_str='Dialer Menu') # self.send_cmd_and_expect(expect_str='Enter 2 to answer call', timeout=60) #wait incoming call # self.send_cmd_and_expect('2', expect_str='Call State: Active call',timeout=10) # self.send_cmd_and_expect('0', expect_str='Telematics SDK') #exit Data Menu # self.exit_test('0') # def Hangup(self): # """挂断电话""" # self.open_test('telsdk_console_app') # self.send_cmd_and_expect('2', expect_str='Dialer Menu') # self.send_cmd_and_expect('4 1') # self.send_cmd_and_expect('4 2') # self.send_cmd_and_expect('0', expect_str='Telematics SDK') #exit Data Menu # self.exit_test('0') # def AirplaneSIM(self): # """SIM卡飞行模式""" # self.open_test('telsdk_console_app') # self.send_cmd_and_expect('1', expect_str='Phone Menu') # self.send_cmd_and_expect('6', expect_str='Enter Operating Mode') # self.send_cmd_and_expect('1') # self.send_cmd_and_expect('0', expect_str='Telematics SDK') #exit Data Menu # self.exit_test('0') # def OnlineSIM(self): # """SIM ONLINE""" # self.open_test('telsdk_console_app') # self.send_cmd_and_expect('1', expect_str='Phone Menu') # self.send_cmd_and_expect('6', expect_str='Enter Operating Mode') # self.send_cmd_and_expect('0') # self.send_cmd_and_expect('0', expect_str='Telematics SDK') #exit Data Menu # self.exit_test('0') # def DisableIMS(self): # """电话关机""" # self.open_test('telsdk_console_app') # self.send_cmd_and_expect('10', expect_str='IMS Settings Menu') # self.send_cmd_and_expect('2', expect_str='Available IMS Service configurations') # self.send_cmd_and_expect('1', expect_str='Enable/Disable config') # self.send_cmd_and_expect('0', expect_str='Select the configuration type') # self.send_cmd_and_expect('q', expect_str='VOIMS is disabled') # self.send_cmd_and_expect('0', expect_str='Telematics SDK') # self.exit_test('0') # def EnableIMS(self): # """电话开机""" # self.open_test('telsdk_console_app') # self.send_cmd_and_expect('10', expect_str='IMS Settings Menu') # self.send_cmd_and_expect('2', expect_str='Available IMS Service configurations') # self.send_cmd_and_expect('1', expect_str='Enable/Disable config') # self.send_cmd_and_expect('1', expect_str='Select the configuration type') # self.send_cmd_and_expect('q', expect_str='VOIMS is enabled') # self.send_cmd_and_expect('0', expect_str='Telematics SDK') # self.exit_test('0') 根据上面提供的函数编写测试脚本: 用例编号:MT273X.DRJK.PTC.SYS.NET.DEV.PHY.002.002 用例名称:MT2735_东软CN_以太网驱动适配_SGMII/RGMII驱动切换 开发单:AN758CNH06-105 前置条件: 1.ADP或客户样机一台 测试步骤: 1.开机上电后,查询串口日志是否有RGMII Mode的打印 2.给C56输入高电平,重启模组或样机查看日志是否有RGMII Mode的打印 预期结果: 1.有RGMII Mode的打印 2.有RGMII Mode的打印
09-19
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值