Как получить имя файла устройства из вывода lsusb или по пути устройства

Вопрос или проблема

Связанный вопрос: Уведомление о подключении/отключении USB

Когда устройство подключается/отключается, я получаю мгновенное уведомление, это здорово. Но чтобы сделать это (почти) идеально, я также хочу получить имя файла устройства, например /dev/ttyUSB0, и, еще лучше, все символические ссылки на него.

Но я не могу найти, как получить эту информацию из udev, или из lsusb, или каким-либо другим способом. Единственный идентификатор устройства, который у меня есть, это путь к устройству, например /devices/pci0000:00/0000:00:1d.0/usb5/5-1. Как получить имя файла устройства из этого?

Предположим, я пытаюсь найти устройство для своей UVC-камеры, lsusb выдает мне:

Bus 001 Device 004: ID 1e4e:0102 Cubeternet GL-UPC822 UVC WebCam

Имя файла устройства тогда /dev/bus/usb/001/004 (первая компонента – это идентификатор шины, следующая – идентификатор устройства).

Я только что составил скрипт для этого, он не очень красивый, но работает для меня.

Я протестировал этот скрипт на Arch Linux с этой конфигурацией:

$ uname -a
Linux 4.4.13-1-lts #1 SMP Wed Jun 8 16:44:31 CEST 2016 x86_64 GNU/Linux

И имя моего устройства /dev/sdb, которое довольно отличается от вашего, надеюсь, оно тоже будет работать для вас.

Также обратите внимание, что этот скрипт зависит от пакета usbutils для программы usb-devices, я полагаю, он установлен по умолчанию во всех дистрибутивах Linux, но могу ошибаться.

Скрипт usbname:

#!/usr/bin/bash

# Входные данные должны быть одной строкой из вывода lsusb:
DATA=$1

# Чтение номера шины:
BUS=`echo $DATA | grep -Po 'Bus 0*\K[1-9]+'`

# Чтение номера устройства:
DEV=`echo $DATA | grep -Po 'Device 0*\K[1-9]+'`

FOUND=false
USB_Serial=""

# Поиск серийного номера флешки:
while read line
do
  if [ $FOUND == true ]; then
    USB_Serial=`echo "$line" | grep -Po 'SerialNumber=\K.*'`
    if [ "$USB_Serial" != "" ]; then
      break;
    fi
  fi

  if [ "`echo "$line" | grep -e "Bus=0*$BUS.*Dev#= *$DEV"`" != "" ]; then
    FOUND=true
  fi
done <<< "$(usb-devices)"

# Получение базового имени блочного устройства, например: "sdx"
BASENAME=`file /dev/disk/by-id/* | grep -v 'part' | grep -Po "$USB_Serial.*/\K[^/]+$"`

# Построение полного адреса, например: "/dev/sdx"
NAME="/dev/$BASENAME"

# Вывод адреса:
echo $NAME

Использование:

$ ./usbname "$(lsusb | grep '<my_usb_label_or_id>')"
/dev/sdb

Я использую эту небольшую bash-функцию

getdevice() {
    idV=${1%:*}
    idP=${1#*:}
    for path in `find /sys/ -name idVendor | rev | cut -d/ -f 2- | rev`; do
        if grep -q $idV $path/idVendor; then
            if grep -q $idP $path/idProduct; then
                find $path -name 'device' | rev | cut -d / -f 2 | rev
            fi
        fi
    done
}

Пример

# lsusb
Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 001 Device 005: ID 8087:0a2b Intel Corp.
Bus 001 Device 012: ID 0bda:2832 Realtek Semiconductor Corp. RTL2832U DVB-T
Bus 001 Device 053: ID 051d:0002 American Power Conversion Uninterruptible Power Supply
Bus 001 Device 051: ID 1cf1:0030 Dresden Elektronik
Bus 001 Device 006: ID 1a86:7523 QinHeng Electronics HL-340 USB-Serial adapter
Bus 001 Device 004: ID 05e3:0606 Genesys Logic, Inc. USB 2.0 Hub / D-Link DUB-H4 USB 2.0 Hub
Bus 001 Device 003: ID 0658:0200 Sigma Designs, Inc. Aeotec Z-Stick Gen5 (ZW090) - UZB
Bus 001 Device 002: ID 0a12:0001 Cambridge Silicon Radio, Ltd Bluetooth Dongle (HCI mode)
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub

и соответствующие устройства

# getdevice 051d:0002
hiddev0
hidraw0

# getdevice 1a86:7523
ttyUSB0

# getdevice 0658:0200
ttyACM1

Если так случится, что USB-устройство является модемом GSM/LTE, то вы можете использовать ModemManager CLI, чтобы получить такую информацию. Команда ниже перечисляет все такие подключенные модемы:

mmcli --list-modems

Вывод даст вам числовые идентификаторы, которые основаны на нулях. Чтобы получить детали для первого модема, используйте команду:

mmcli -m 0

Среди прочих строк вывод будет содержать что-то вроде этого:

  System   |            device: /sys/devices/pci0000:00/0000:00:08.1/0000:03:00.3/usb1/1-2
           |           drivers: option, cdc_ether
           |            plugin: huawei
           |      primary port: ttyUSB2
           |             ports: ttyUSB0 (at), ttyUSB1 (qcdm), ttyUSB2 (at), 
           |                    wwx025003100000 (net)

Ответ или решение

Для получения имени устройства в Linux из вывода команды lsusb или по пути устройства, необходимо осуществить несколько действий. Ниже представлен подробный ответ, который включает необходимые шаги и примеры кода.

1. Использование команды lsusb

Команда lsusb позволяет получить информацию о подключенных USB-устройствах. Она выводит список всех USB-устройств с их уникальными идентификаторами, представляющими собой комбинацию ID производителя и продукта. Пример вывода команды:

Bus 001 Device 004: ID 1e4e:0102 Cubeternet GL-UPC822 UVC WebCam

2. Определение устройства по ID

Когда вы знаете ID производителя и ID продукта, можно использовать их для определения соответствующего устройства. Например, ID 1e4e:0102 указывает на конкретное устройство. Теперь мы можем использовать этот ID для получения информации о файле устройства, например, /dev/ttyUSB0.

3. Получение файлового имени устройства

Для этого можно использовать usb-devices, чтобы найти, какому файловому имени соответствует данное устройство. Таким образом, вы можете создать Bash-скрипт, который принимает строку из lsusb и возвращает путь к устройству.

Пример скрипта, который находит имя устройства:

#!/usr/bin/env bash

# Входные данные: строка из вывода lsusb
DATA=$1

# Получение информации о шине и устройстве
BUS=$(echo "$DATA" | grep -Po 'Bus 0*\K[1-9]+')
DEV=$(echo "$DATA" | grep -Po 'Device 0*\K[1-9]+')

# Инициализация переменной для хранения серийного номера
FOUND=false
USB_Serial=""

# Поиск серийного номера устройства
while read -r line; do
  if [ "$FOUND" == true ]; then
    USB_Serial=$(echo "$line" | grep -Po 'SerialNumber=\K.*')
    if [ "$USB_Serial" != "" ]; then
      break
    fi
  fi

  if grep -q "Bus=0*$BUS.*Dev#= *$DEV" <<< "$line"; then
    FOUND=true
  fi
done < <(usb-devices)

# Получение базового имени блочного устройства
BASENAME=$(file /dev/disk/by-id/* | grep -v 'part' | grep -Po "$USB_Serial.*/\K[^/]+$")

# Формирование полного пути
NAME="/dev/$BASENAME"

# Вывод результата
echo $NAME

4. Использование функции Bash для получения имени устройства

Вы также можете создать функцию в Bash, которая делает это. Пример функции:

getdevice() {
    idV=${1%:*}  # ID производителя
    idP=${1#*:}  # ID продукта
    for path in $(find /sys/ -name idVendor | rev | cut -d/ -f 2- | rev); do
        if grep -q $idV $path/idVendor; then
            if grep -q $idP $path/idProduct; then
                find $path -name 'device' | rev | cut -d / -f 2 | rev
            fi
        fi
    done
}

5. Получение информации о модемах

Если устройство является модемом, можно использовать ModemManager. Команда mmcli --list-modems позволяет получить список модемов, а mmcli -m <номер> дает подробную информацию о них, включая путь к устройству.

Заключение

Используя указанные методы, вы сможете получить имя устройства, подключенного через USB, по его идентификатору или пути. Если вам нужно более сложное решение или если устройство специфично, могут потребоваться дополнительные шаги, однако рассмотренные подходы охватывают большинство распространенных случаев.

Оцените материал
Добавить комментарий

Капча загружается...