superloopnetworks
superloopnetworks

Reputation: 514

Subprocess command with quotes not working

My subprocess command is not working with quotes.

tail = subprocess.Popen('tail -f -n 1 /mnt/syslog/**/*.log | egrep -v \'^$|mnt\'',\
            shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)

When I execute python file.py I get a empty line:

# python main.py 
^CTraceback (most recent call last):
  File "main.py", line 18, in <module>
    main()
  File "main.py", line 12, in main
    line = tail.stdout.readline()
KeyboardInterrupt

It works fine in bash as you can see:

# tail -f -n 1 /mnt/syslog/**/*.log | egrep -v '^$|mnt'
Sep  9 22:44:07 x.x.x.x : %LINK-3-UPDOWN: Interface GigabitEthernet1/0/19, changed state to down
Sep  9 18:32:56 x.x.x.x : %LINK-5-CHANGED: Interface GigabitEthernet1/0/24, changed state to administratively down

What is wrong?

Upvotes: 2

Views: 872

Answers (2)

stachel
stachel

Reputation: 135

You need to run communicate() on Popen instance. It should look like

tail = subprocess.Popen('tail -f -n 1 /mnt/syslog/**/*.log | egrep -v \'^$|mnt\'',
                        shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
stdout, stderr = tail.communicate()
print(stdout)

If you need unicode string instead of bytes use decode():

print(stdout.decode())

Update: Because of -f flag to tail you should get output live:

tail = subprocess.Popen('tail -f -n 1 /mnt/syslog/**/*.log | egrep -v \'^$|mnt\'',
                        shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
for line in tail.stdout:
    print(line)

It's not best method, more you can find in this topic.

Upvotes: 1

Sean Suchter
Sean Suchter

Reputation: 338

I don't think the problem is the quotes at all.

The command is doing tail -f, which by definition never terminates (it keeps tailing the file(s)). When you call it at the shell, you immediately see some output (maybe, depending on whether the grep matches). But it probably doesn't return to the prompt, because the tail is still running.

If you really want to be following the file, then you shouldn't be using communicate() as that expects a terminating process. You have to keep reading from stdout (and stderr, to be safe!) until the process dies.

But I suspect that all you need to do is to remove the -f on the tail:

tail = subprocess.Popen('tail -n 1 /mnt/syslog/**/*.log | egrep -v \'^$|mnt\'',\
        shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)

If you remove the -f, then communicate() is exactly the right call to use.

Or, you can just use the check_output helper:

subprocess.check_output('tail...', shell=True)

Upvotes: 1

Related Questions