Capturing LIVE output of shell script while runnin

2019-06-09 18:14发布

I am writing a python script to ssh into a linux server and execute a shell script that is already stored on the linux server.

Here is what my code look like so far

command = ['ssh into the remote server',
           'cd into the directory of the shell script,
           './running the shell script',
           ]

process = subprocess.Popen(command,
                            shell=True,
                            stdin=subprocess.PIPE,
                            stdout=subprocess.PIPE,
                            stderr=subprocess.PIPE)

err, out = process.communicate()

if out: 
    print "standard output of subprocess is : "
    print out
if err:
    print "standard error of subprocess is : "
    print err
print "returncode of subprocess: "
print process.returncode

1st question: I can obtain the output of my shell scripts through stderr, but I only obtain it after the entire shell script has finished executing. So if the shell script takes 10 minutes to finish, I only get to see the output of the shell script after 10 minutes. I want to have the output of my shell scripts return line by line to me just as if I was executing the script manually in the remote server. Can this be done?

2nd question: as you can see, I have three commands in my command list (which is only a small portion of all my commands,) if I put all my commands in the list, I only obtain the output of ALL my commands through stdout ONLY when all my commands has finished executing. If my 1st question cannot be done, is there a way to at least obtain the output of each command after each one has been executed instead of receiving them all at once only when all the commands has finished being executed.

3条回答
狗以群分
2楼-- · 2019-06-09 18:22

To see the output immediately, don't redirect it:

from subprocess import Popen, PIPE

p = Popen(['ssh', 'user@hostname'], stdin=PIPE) 
p.communicate(b"""cd ..
echo 1st command
echo 2nd command
echo ...
""")

If you want both to capture the "live" output in a variable and to display it in the terminal then the solution depends on whether you need to handle stdin/stdout/stderr concurrently.

If input is small and you want to combine stdout/stderr then you could pass all commands at once and read the merged output line-by-line:

from subprocess import Popen, PIPE, STDOUT

p = Popen(['ssh', 'user@hostname'], stdin=PIPE,
          stdout=PIPE, stderr=STDOUT, bufsize=1) 
p.stdin.write(b"""cd ..
echo 1st command
echo 2nd command
echo ...
""")
p.stdin.close() # no more input

lines = [] # store output here
for line in iter(p.stdout.readline, b''): # newline=b'\n'
    lines.append(line) # capture for later
    print line, # display now
p.stdout.close()
p.wait()

If you want to capture "live" stdout/stderr separately, see:

查看更多
等我变得足够好
3楼-- · 2019-06-09 18:23

I'm not entirely sure, but maybe you get instant output if you pass the other two commands as arguments to ssh:

command = 'ssh user@example.com \'cd some/path/on/your/server; ./run-the-script.sh\''

The way I understand it, Python first reads and processes all the input and only then returns output. I'm not too familiar with Python, so I might be wrong on this, but if I'm right, this should help.

查看更多
对你真心纯属浪费
4楼-- · 2019-06-09 18:35

Don't call .communicate() -- that waits for the process to finish.

Instead, keep reading data from .stdout pipe.

Simple example:

In [1]: import subprocess
In [2]: p = subprocess.Popen(["find", "/"], stdout=subprocess.PIPE)


In [3]: p.stdout
Out[3]: <open file '<fdopen>', mode 'rb' at 0x7f590446dc00>

In [4]: p.stdout.readline()
Out[4]: '/\n'

In [5]: p.stdout.readline()
Out[5]: '/var\n'

In [6]: p.stdout.readline()
Out[6]: '/var/games\n'
查看更多
登录 后发表回答