0

I am trying to run a usbreset program against lsusb which has several devices with the same device identifier.

I run lsusb to list the devices, and add a | grep [identifer] to only list the devices with that identifier.

I need to then run an awk command to get the bus and device number, which will be inserted into a usbreset program (https://github.com/jkulesza/usbreset) which will reset all of the devices that match the id.

The command looks like this:

lsusb | grep 1234:a1b1 | while read line ; do awk -F '[^0-9]+' '{ system("sudo ./usbreset /dev/bus/usb/002/"$3) }'; done

where -F '[^0-9]+' helps remove the ":" from the end of the device number, and $3selects the fourth column of the lsusb command output: Bus 002 Device 010: ID 1234:a1b1

This works nicely, but the issue I have is that i have 6 devices with this id, and the awk command cuts off the first result, and only prints 5.

user@localhost:~$ lsusb | grep 1234:a1b1
Bus 002 Device 015: ID 1234:a1b1
Bus 002 Device 014: ID 1234:a1b1
Bus 002 Device 013: ID 1234:a1b1
Bus 002 Device 010: ID 1234:a1b1
Bus 002 Device 009: ID 1234:a1b1
Bus 002 Device 008: ID 1234:a1b1

and:

user@localhost:~$ lsusb | grep 1234:a1b1 | while read line ; do awk -F '[^0-9]+' '{ print $3 }'; done
014
013
010
009
008

Any advice to help find out where I am going wrong with this would be great!

  • 2
    You're read ing (and discarding) the first line, then awking what remains – steeldriver Feb 28 '20 at 15:54
  • Try this: lsusb | grep "1234:a1b1" | awk '{printf $4 "\n"}' – s3n0 Feb 28 '20 at 17:00
  • @s3n0: In light of StephenKitt's better answer below, this is like kicking a dead horse, but ignoring lsusb' filtering ability for a moment, simplify this to: $ for device in $(cut -c16-18 <(grep "1234:a1b1" <(lsusb))); do ... ; done. In doing so, you avoid pipes as well as get rid of a spurious colon in the output. It's short enough that it's still readable. – Cbhihe Feb 29 '20 at 16:39
  • @Cbhihe : You're wrong because, for example, in the lightweight version of Linux, under BusyBox, there is no -d argument for lsusb. So this syntax is useless in this case. I personally always try to create a Shell command-line that works everywhere. – s3n0 Feb 29 '20 at 19:13
  • @s3n0: "personally" read my comment better... especially the part that reads: "ignoring lsusb filtering ability for a moment,..." – Cbhihe Feb 29 '20 at 20:45

2 Answers2

4

The line is disappearing because of the read line invocation, not AWK. I would go about this differently:

lsusb -d 1234:a1b1 | while read _ bus _ device _; do
    sudo ./usbreset "/dev/bus/usb/${bus}/${device%:}"
done

This uses lsusb’s own ability to filter devices, then reads the bus and device identifiers into the corresponding variables, and gives the appropriate values to usbreset, stripping the trailing “:” from ${device}.

Stephen Kitt
  • 434,908
1

@StephenKitt's shell loop is fine in this case since efficiency probably isn't an issue and the input format is well known and simple and you're not just manipulating text (see why-is-using-a-shell-loop-to-process-text-considered-bad-practice) but another option without writing a loop would presumably be:

lsusb -d '1234:a1b1' |
    awk -F'[ :]' '{printf "/dev/bus/usb/%s/%s\n", $2, $4}' |
    xargs -n 1 sudo ./usbreset
Ed Morton
  • 31,617