Flask中执行sudo iwlist wlan0 scan异常问题求助
问题描述
我正在更新树莓派上的Python 3.x应用,想要实现扫描附近WiFi网络的功能,但执行sudo iwlist wlan0 scan时遇到问题:
- 独立脚本中执行该命令完全正常,能返回WiFi列表
- 在Flask应用中以同一用户执行时,要么无输出,要么报错
[Errno 2] No such file or directory: 'sudo'
测试情况
独立脚本(正常运行)
import os import getpass import subprocess output = os.popen("sudo iwlist wlan0 scan").read() # 独立运行时正常工作 print(output) print(f'Effective user is {getpass.getuser()}')
执行输出:
pi@BenchPi3BPlus:~ $ python3 test.py wlan0 Scan completed : Cell 01 - Address: 11:22:BF:21:33:44 Channel:1 <edit> Cell 10 - Address: 55:55:EB:66:77:25 Channel:5 <edit> Effective user is pi pi@BenchPi3BPlus:~ $
Flask中执行(无输出)
app.logger.debug(f'Effective user is {getpass.getuser()}') output = os.popen("sudo iwlist wlan0 scan").read() app.logger.debug(f'SUCCESS: {output}')
日志输出:
[2023-11-06 09:49:54 +1100] [3983] [DEBUG] GET /network [2023-11-06 09:49:55 +1100] [3983] [DEBUG] Effective user is pi [2023-11-06 09:49:55 +1100] [3983] [DEBUG] SUCCESS:
改用subprocess.Popen(Flask中报错)
import os import getpass import subprocess cmd = ["sudo", "iwlist", "wlan0", "scan"] result = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=False, encoding='utf-8') (stdoutdata, stderrdata) = result.communicate() if stdoutdata: print(stdoutdata.strip()) if stderrdata: print(stderrdata.strip()) print(f'Effective user is {getpass.getuser()}')
Flask日志输出:
[2023-11-09 09:24:45 +1100] [11683] [DEBUG] GET /network [2023-11-09 09:24:46 +1100] [11683] [DEBUG] Effective user is pi [2023-11-09 09:24:46 +1100] [11683] [DEBUG] runSubprocess threw: [Errno 2] No such file or directory: 'sudo'
解决方案
1. 使用命令的绝对路径
Flask运行时的环境变量PATH可能和终端不同,导致找不到sudo或iwlist。先在终端查绝对路径:
which sudo # 通常输出 /usr/bin/sudo which iwlist # 通常输出 /sbin/iwlist
然后在代码中替换为绝对路径:
# os.popen写法 output = os.popen("/usr/bin/sudo /sbin/iwlist wlan0 scan").read() # subprocess写法 cmd = ["/usr/bin/sudo", "/sbin/iwlist", "wlan0", "scan"] result = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=False, encoding='utf-8')
2. 给pi用户免密执行iwlist命令
避免使用sudo,直接给pi用户授权无需密码执行iwlist wlan0 scan:
- 编辑sudoers文件:
sudo visudo
- 在文件末尾添加一行:
pi ALL=(ALL) NOPASSWD: /sbin/iwlist wlan0 scan
- 保存退出后,代码中直接执行命令,去掉
sudo:
# os.popen写法 output = os.popen("/sbin/iwlist wlan0 scan").read() # subprocess写法 cmd = ["/sbin/iwlist", "wlan0", "scan"] result = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=False, encoding='utf-8')
3. 检查并设置Flask的PATH环境变量
在Flask代码中打印当前PATH,确认是否包含sudo和iwlist所在目录:
app.logger.debug(f"Current PATH: {os.environ.get('PATH')}")
如果缺少/usr/bin或/sbin,手动添加:
import os os.environ['PATH'] += ':/usr/bin:/sbin'
之后再执行命令即可。
4. 改用subprocess.check_output简化写法
推荐使用更安全的subprocess.check_output,同时捕获异常:
import subprocess try: output = subprocess.check_output(["/usr/bin/sudo", "/sbin/iwlist", "wlan0", "scan"], encoding='utf-8') app.logger.debug(f'SUCCESS: {output}') except subprocess.CalledProcessError as e: app.logger.debug(f'Error: {e.stderr}')
内容的提问来源于stack exchange,提问作者greiginsydney
相关产品推荐
相关产品推荐

