I've written a few shell scripts, but have never seen this behavior and am at a loss. I've got the following simple script which runs in a bash shell:



VENDOR=$(lsusb -D "$DEVICE" | grep idVendor 2>&1)

{"data": {
    "action": "add",
    "port": {
        "type": "$SUBSYSTEM",
    "drive": {
        "vendor_id": "$VENDOR",

printf "output: $VENDOR" >> $LOGFILE
printf "%s\n" "`date +%x\ %r\ %Z` $REQUEST"  >> $LOGFILE

This is executed from a udev rule. The positional parameters (coming from udev) have the values I expect, and I have no problem printing them to the log file. But for some reason, the $VENDOR variable contains no output from the lsusb command.

Here is the debugging I've done.

  • Added stderr redirection to stdout to capture any error that may be occurring.
  • Added the line to send the $VENDOR variable directly to the log, which is empty.
  • Executed the script manually in the shell and printed the $VENDOR variable to the terminal and it's empty.
  • Took the string that is contained in the $DEVICE variable and executed it directly in the shell, with this result.

    [root@host ~]# lsusb -D /dev/bus/usb/016/030 | grep idVendor
    Cannot open /dev/bus/usb/016/030

Why is the $VENDOR variable empty when outputting to the log file?


Here is an update after removing the redirection from the command substitution.

  • Added a line to print the $VENDOR variable to the terminal.
  • Statically assigned the value instead of using the $DEVICE variable.

Printing $VENDOR to the terminal output the error, but it still did not append to the log file! The value of $DEVICE IS in the log file. I believe it has something to do with the output redirection inside the command substitution.

  • Welcome to U&L , what is the output of ls /dev/bus/usb/*? You can edit here
    – GAD3R
    Commented Dec 21, 2017 at 5:16
  • 1
    The error Cannot open /dev/bus/usb/016/030 mean that 016:030 device doesn't exist.
    – GAD3R
    Commented Dec 21, 2017 at 5:29
  • On that bus it shows /proc/bus/usb/016: 001 002 053 But it gets that path dynamically from udev, and when i look in the log file 053 is the path it's printing so I know its getting the correct path of the device. Commented Dec 21, 2017 at 5:31
  • @GAD3R - /dev/bus/usb/016/030 was not in fact the correct path. I just used it for testing to see if I could get any output. Point being that it should have written that error to the log. Commented Dec 21, 2017 at 5:33
  • It's not the permissions because it does write to the log file. Only the output coming from lsusb is missing. But after thinking more about it I think that could be because lsusb is not running properly from the udev rule. Possibly because it is not running in the normal shell environment. Commented Dec 21, 2017 at 6:09

1 Answer 1


Here, if lsusb drops an error, the error message is not redirected, only errors from grep. Errors from lsusb still go the the usual stderr, i.e. the terminal (or whatever stderr was when the script started.

VENDOR=$(lsusb -D "$DEVICE" | grep idVendor 2>&1)


$ blah=$(ls -l /nonexisting | grep foo 2>&1)
ls: cannot access '/nonexisting': No such file or directory
$ echo "blah: '$blah'"
blah: ''

You'll need to redirect both of their outputs as a group to have the command substitution capture the error, too:

$ blah=$( { ls -l /nonexisting | grep foo; } 2>&1)
$ echo "blah: '$blah'"
blah: 'ls: cannot access '/nonexisting': No such file or directory'

Using separate redirections like $( foo 2>&1 | grep 2>&1 ) would send the errors of the first command to the pipe, and for grep to filter, which in the above example would again produce an empty output.

  • Thanks a bunch! I was able to get stderr that way, and as I suspected there was an error. I'm seeing lsusb: command not found, but now I have to figure out what is causing that. Commented Dec 21, 2017 at 6:45

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .