Ansible如何优雅获取打印机USB路径?替代shell模块的方案
问题
我正在为Raspberry Pi 4编写Ansible playbook,其中的podman容器需要访问位于/dev/bus/usb/XXX/YYY路径的打印机设备。目前我已通过shell模块实现该功能,但shell模块并不推荐使用,现有任务代码如下:
- name: "ScannerJS - Detect printer's USB bus" block: - name: "ScannerJS - Detect printer's USB bus" ansible.builtin.shell: | set -e -o pipefail lsusb | grep Epson | awk '{print "/dev/bus/usb/"$2"/"substr($4, 1, length($4)-1)}' args: executable: /bin/bash register: scUSBBus failed_when: scUSBBus.stdout | regex_search("^\/dev\/bus\/usb\/(\\d{3})\/(\\d{3})$") is none - name: "ScannerJS - assert the device path exists" ansible.builtin.stat: path: "{{ scUSBBus.stdout }}" register: scUSBBusStat failed_when: scUSBBusStat.stat.exists is not true
请问是否有更规范的方式获取该打印机的USB总线路径?我已尝试查看Ansible facts,但未找到USB设备相关信息,也未发现对应模块。
解决方案
可以通过读取系统sysfs文件系统的USB设备信息,或者使用第三方Ansible模块来替代shell命令,避免依赖外部工具,更符合模块化规范。
方案1:基于sysfs的原生模块实现
利用Ansible的find、lookup等模块直接读取系统USB设备的标识文件,无需调用外部命令:
- name: "ScannerJS - 获取Epson打印机的USB设备路径" block: - name: "ScannerJS - 枚举所有USB根设备目录" ansible.builtin.find: paths: "/sys/bus/usb/devices" patterns: "usb*" recurse: false file_type: directory register: usb_devices - name: "ScannerJS - 筛选Epson设备并提取总线/设备号" ansible.builtin.set_fact: epson_usb_path: "{{ item }}" loop: "{{ usb_devices.files | map(attribute='path') | list }}" vars: # 替换为你的Epson设备厂商ID,可通过lsusb查询,Epson通用ID为04b8 target_vendor_id: "04b8" device_vendor_id: "{{ lookup('file', item ~ '/idVendor') | trim }}" when: device_vendor_id == target_vendor_id no_log: true - name: "ScannerJS - 生成/dev/bus/usb完整路径" ansible.builtin.set_fact: scUSBBus: >- /dev/bus/usb/ {{ epson_usb_path | regex_search('usb(\\d+)', '\\1') | first }}/ {{ epson_usb_path | basename | regex_search('(\\d+)-', '\\1') | first }} when: epson_usb_path is defined - name: "ScannerJS - 验证设备路径存在" ansible.builtin.stat: path: "{{ scUSBBus }}" register: scUSBBusStat failed_when: not scUSBBusStat.stat.exists
说明
- 通过
find模块遍历系统USB设备的根目录 - 读取每个设备的
idVendor文件,匹配Epson的厂商ID来筛选目标设备 - 用正则从设备路径中提取总线号和设备号,拼接成
/dev/bus/usb下的完整路径 - 最后验证路径的有效性
方案2:使用第三方USB设备模块
如果可以安装第三方集合,community.general.usb_device模块能直接返回USB设备的结构化信息,代码更简洁:
- 先安装对应的Ansible集合:
ansible-galaxy collection install community.general
- 在playbook中使用该模块:
- name: "ScannerJS - 获取Epson打印机USB信息" community.general.usb_device: state: list register: usb_devices - name: "ScannerJS - 筛选Epson设备并生成路径" ansible.builtin.set_fact: scUSBBus: "/dev/bus/usb/{{ item.bus_number }}/{{ item.device_number }}" loop: "{{ usb_devices.devices }}" when: item.vendor == 'Epson' - name: "ScannerJS - 验证设备路径存在" ansible.builtin.stat: path: "{{ scUSBBus }}" register: scUSBBusStat failed_when: not scUSBBusStat.stat.exists
说明
- 模块会直接返回所有USB设备的
bus_number和device_number字段,直接拼接即可得到目标路径 - 无需手动处理系统文件,代码可读性更高
内容的提问来源于stack exchange,提问作者tholeb
相关产品推荐
相关产品推荐

