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


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

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 at 15:54
  • Try this: lsusb | grep "1234:a1b1" | awk '{printf $4 "\n"}' – s3n0 Feb 28 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 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 at 19:13
  • @s3n0: "personally" read my comment better... especially the part that reads: "ignoring lsusb filtering ability for a moment,..." – Cbhihe Feb 29 at 20:45

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%:}"

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}.

| improve this answer | |
  • I thought it was easier than I expected.. Thanks! You taught me a useful skill today! – I_Literally_Cannot Feb 28 at 17:22

@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
| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.