求助:修正Bash脚本以正确提取Windows驱动INF文件的硬件ID并构建MySQL数据库
我正在开发一个Windows 10/11驱动自动安装系统,之前从DriverPack下载了驱动合集(合集本身没问题,但配套的安装管理软件疑似带病毒)。现在我可以安装几乎所有Windows驱动,但每次搜索正确的.inf文件耗时极长——驱动合集存在我那台Ubuntu 22.04.1服务器(命名为FREEBNT)的SAMBA共享里,每次安装要花20多分钟才能定位到目标.inf。
最近我想到一个优化方案:用MySQL搭建一个硬件ID与.inf文件路径的映射数据库,再写PowerShell脚本通过数据库配合SAMBA快速下载安装驱动。ChatGPT帮我生成了基础代码,但目前卡在第一步——生成数据库的Bash脚本有问题,无法正确提取INF文件里的硬件ID。
FREEBNT同时担任MySQL服务器和SAMBA服务器,我打算在这台机器上运行Bash脚本,把所有.inf文件的硬件ID和对应的Windows可访问路径导入数据库。
我当前使用的Bash脚本
#!/bin/bash # Set up MySQL database connection parameters db_user="mymysqluser" db_pass="mymysqlpass" db_name="drivers" db_host="127.0.0.1" # Set up the path to your drivers collection drivers_path="/free/fr/drivers/" # Loop through all INF files in the drivers collection for inf_file in $(find "$drivers_path" -type f -name "*.inf"); do # Extract hardware IDs from INF file hwids=$(grep -iE "^driverver|^pci|usb\\\\" "$inf_file" | awk -F ",|=" '{print $2}' | tr -d ' ' | sort -u) #convert the inf file path to a path readable by Windows systems through SAMBA (added by borhacker) inf_file2=$(echo $inf_file | sed 's/\/free\/fr\/drivers\//\\\\192.168.1.2\\Fr-drivers\\/') inf_file3=$(echo $inf_file2 | sed 's/\//\\/g') # Loop through all hardware IDs and insert them into the database for hwid in $hwids; do echo "Inserting $hwid for $inf_file3 into database..." mysql -u $db_user -p$db_pass -h $db_host $db_name -e "INSERT INTO drivers (hwid, path) VALUES ('$hwid', '$inf_file3');" done done
我已完成的修改
我自己添加了路径转换逻辑,能把Linux下的路径:/free/fr/drivers/bluetooth/DP_Bluetooth_22094/MediaTek/FORCED/10x64/7921_1.3.14.133_tequila/mtkbtfilter.inf
转换成Windows能识别的SAMBA路径:\\192.168.1.2\Fr-drivers\bluetooth\DP_Bluetooth_22094\MediaTek\FORCED\10x64\7921_1.3.14.133_tequila\mtkbtfilter.inf
这部分功能正常,没有问题。
当前遇到的问题
我搞不懂脚本里提取硬件ID的那段代码,现在运行脚本时,提取出来的根本不是硬件ID,而是驱动版本日期之类的内容,比如运行输出:
root@freebnt:/home/borhacker# ./indexdrivers-edit.sh Inserting 07/10/2016 for \\192.168.1.2\Fr-drivers\video\DP_Video_nVIDIA-XP_22080\nVidia\FORCED\5x86\368.81\nvmmi.inf into database... mysql: [Warning] Using a password on the command line interface can be insecure. Inserting 07/10/2016 for \\192.168.1.2\Fr-drivers\video\DP_Video_nVIDIA-XP_22080\nVidia\FORCED\5x86\368.81\nvbli.inf into database... mysql: [Warning] Using a password on the command line interface can be insecure. ...
我需要修正这段提取硬件ID的代码,让脚本能正确识别INF文件里的硬件ID(比如PCI\VEN_10DE&DEV_1C82、USB\VID_046D&PID_C52F这类格式),并正确插入数据库。
问题根源与修正方案
1. 问题出在哪?
原来的grep命令错误匹配了^driverver(这是驱动版本行,格式为DriverVer=07/10/2016,368.81,awk提取第二个字段自然拿到日期),同时错误匹配^pci(硬件ID不会以pci开头,而是PCI\),导致完全提取不到正确的硬件ID。
2. 正确的硬件ID提取逻辑
Windows INF文件里的硬件ID通常在[Manufacturer]对应的设备项中,格式为PCI\VEN_XXXX&DEV_XXXX、USB\VID_XXXX&PID_XXXX、ACPI\XXXX等,一般出现在等号后方,部分行还会用逗号分隔多个硬件ID。
此外,部分INF文件采用UTF-16LE编码(Windows默认),直接用grep读取会乱码,需要先转码为UTF-8。
3. 修正后的完整脚本
#!/bin/bash # Set up MySQL database connection parameters db_user="mymysqluser" db_pass="mymysqlpass" db_name="drivers" db_host="127.0.0.1" # Set up the path to your drivers collection drivers_path="/free/fr/drivers/" # Loop through all INF files in the drivers collection find "$drivers_path" -type f -name "*.inf" | while read -r inf_file; do # 处理INF文件编码:尝试转码为UTF-8,失败则直接读取 if iconv -f UTF-16LE -t UTF-8 "$inf_file" >/dev/null 2>&1; then inf_content=$(iconv -f UTF-16LE -t UTF-8 "$inf_file") else inf_content=$(cat "$inf_file") fi # 提取硬件ID:匹配等号后包含PCI\、USB\、ACPI\、HID\的内容,处理多个ID的情况 hwids=$(echo "$inf_content" | grep -iE "=.*(PCI\\\USB\\\ACPI\\\HID\\\)" | \ awk -F "=" '{ gsub(/["']/, "", $2) split($2, ids, /,/) for(id in ids) { trimmed = gensub(/^[[:space:]]+|[[:space:]]+$/, "", "g", ids[id]) if (trimmed ~ /^(PCI|USB|ACPI|HID)\\\/) { print trimmed } } }' | tr -d ' ' | sort -u) # 如果没有提取到硬件ID,尝试另一种匹配方式(直接找带VEN_/VID_的行) if [ -z "$hwids" ]; then hwids=$(echo "$inf_content" | grep -iE "(VEN_|VID_)" | \ awk '{ for(i=1; i<=NF; i++) { if ($i ~ /VEN_|VID_/) { gsub(/["']/, "", $i) print $i } } }' | tr -d ' ' | sort -u) fi # 跳过无硬件ID的文件 if [ -z "$hwids" ]; then echo "No hardware IDs found for $inf_file, skipping..." continue fi # 转换为Windows可访问的SAMBA路径 inf_file3=$(echo "$inf_file" | sed 's/\/free\/fr\/drivers\//\\\\192.168.1.2\\Fr-drivers\\/' | sed 's/\//\\/g') # 插入数据库:转义SQL特殊字符避免注入 for hwid in $hwids; do escaped_hwid=$(echo "$hwid" | sed "s/'/''/g") escaped_path=$(echo "$inf_file3" | sed "s/'/''/g") echo "Inserting $escaped_hwid for $escaped_path into database..." mysql -u "$db_user" -p"$db_pass" -h "$db_host" "$db_name" -e "INSERT INTO drivers (hwid, path) VALUES ('$escaped_hwid', '$escaped_path');" done done
4. 额外优化说明
- 增加了编码处理:自动识别UTF-16LE编码的INF文件并转码,避免乱码导致提取失败
- 增加了双重提取逻辑:第一种方式失败时,尝试匹配带
VEN_/VID_的硬件ID - 增加了SQL注入防护:转义字符串中的单引号,避免破坏SQL语句
- 增加了跳过逻辑:对无硬件ID的INF文件直接跳过,减少无效操作
备注:内容来源于stack exchange,提问作者charlesfreejazz

