I've been trying to get the log of unplugged USB devices from dmesg from within a Python script. At the command line, I would type:
dmesg | tail -100 | grep "USB disconnect" and see the desired output. Within the script I have been using the subprocess.run command but it seems to have an issue with the pipe redirection, since if I simply use "dmesg" as the subprocess.run argument I do indeed get the entire giant log. Here is an example attempt and its output, along with an attempt to do the same with subprocess.call :
import subprocess
args = ["dmesg | tail -100 | grep \042USB disconnect\042"]
grep_rpt = str(subprocess.call(args[0x00], shell = True))
print(grep_rpt + ", " + str(len(grep_rpt)))
args = ["dmesg", "|", "tail", "-100", "|", "grep", "\042USB disconnect\042"]
shellCmd = subprocess.run(args, capture_output = True, text = True)
grep_rpt = str(shellCmd.stdout)
print(grep_rpt + ", " + str(len(grep_rpt)))
And the output :
[ 4197.327275] usb 1-1.3: USB disconnect, device number 19
[ 4329.665928] usb 1-1.3: USB disconnect, device number 20
[ 4645.282024] usb 1-1.3: USB disconnect, device number 21
[ 4729.497491] usb 1-1.3: USB disconnect, device number 22
[ 4961.154086] usb 1-1.3: USB disconnect, device number 23
[ 5090.165051] usb 1-1.3: USB disconnect, device number 24
[ 5181.803769] usb 1-1.3: USB disconnect, device number 25
[ 5620.543437] usb 1-1.3: USB disconnect, device number 26
[ 5831.722098] usb 1-1.3: USB disconnect, device number 27
[ 7350.416575] usb 1-1.3: USB disconnect, device number 28
[ 7507.328715] usb 1-1.3: USB disconnect, device number 29
0, 1
, 0
This output is a bit deceiving, since the list of devices is the result of the actions of subprocess.call, this is always going out to the screen but is not being sent back as an object, since as you can see I get "0" back as the string. I tried doing capture_output = True to stop this but it appears to not be one of the call() options even though it is for run(). And you can see that run() is returning None. Again, if I just do "dmesg" without the pipes everything is fine. I did try shlex on the arguments for run() but it didn't help. I have also successfully used run() to get data from the i2c bus so I know I am handling the format for multiple arguments correctly. What am I missing here?
After reading some other threads I got the correct output with this :
Although oddly enough subprocess.check_output() did not work. Other discussions on StackOverflow seem to indicate that to get the | pipe result you have to call subprocess multiple times and pass the output of one as the input of the next. I hope that's not really what's happening here as I wanted to have the dmesg output filtered by the kernel and not by Python.