0

I want to run multiple Terminal commands from Python using subprocess and simultaneously not only execute the commands but also print the output that appears in Terminal in full to my stdout, so I can see it in real-time (as I would if making the commands directly in Terminal).

Now, using the advice here I was able to run multiple Bash commands from Python:

def subprocess_cmd(command):
    process = subprocess.Popen(command,stdout=subprocess.PIPE, shell=True)
    proc_stdout = process.communicate()[0].strip()
    print(proc_stdout)

subprocess_cmd('echo a; echo b; cd /home/; ls')

Output:

b'a\nb\n<Files_in_my_home_folder>'

So far so good. But if I try to run ls -w (which should raise an error),

subprocess_cmd('echo a; echo b; cd /home/; ls -w')

output:

b'a\nb'

whereas the error message should be shown as it would in Terminal:

ls: option requires an argument -- 'w'
Try 'ls --help' for more information.

I would like to print out whatever is in Terminal (simultaneously with running the command) for whatever the command is, be it running some executable, or a shell command like ls.

I am using Python 3.7+ so any solution using subprocess.run or similar is also welcome. However, I'm not sure this takes multiple commands together nor does using capture_output=True, text=True print error messages.

  • 1
    Thanks, it worked for me! Might be worth writing up into an answer I can accept – Vainmonde De Courtenay Apr 19 '21 at 12:26
  • If you don't actually want to capture the output, remove the `capture=True` and the `stdout` keyword flag and let the process write to stdout by itself. (Still second the recommendation to not use bare `Popen` unless you specifically know what you are doing.) – tripleee Apr 19 '21 at 13:02
  • @tripleee what do you mean 'remove the `capture=True`'? My code example doesn't include a `capture=True`. That said, I am interested in doing what you say (i.e. printing the output without capturing it) – Vainmonde De Courtenay Apr 19 '21 at 14:34
  • I was sort of divided between commenting on your question, or on the answer you had received at the time; the `capture=True` refers to the solution in @python_user's answer (except of course it's actually written `capture_output=True`, duh). I posted another answer with more details about this now. – tripleee Apr 19 '21 at 15:30

1 Answers1

0

The stdout=subprocess.PIPE (or the shorthand capture_output=True which subsumes this and a few related settings) says that you want Python to read the output. If you simply want the subprocess to spill whatever it prints directly to standard output and/or standard error, you can simply leave out this keyword argument.

As always, don't use Popen if you can avoid it (and usually avoid shell=True if you can, though that is not possible in your example).

subprocess.check_call('echo a; echo b; cd /home/; ls', shell=True)

To briefly reiterate, this bypasses Python entirely, and lets the subprocess write to its (and Python's) standard output and/or standard error without Python's involvement or knowledge. If you need for Python to know what's printed, you'll need to have your script capture it, and have Python print it if required.

tripleee
  • 175,061
  • 34
  • 275
  • 318
  • Thanks, but I actually wanted to print the output to my stdout **in Python**. The only distinction is I wanted this happening in real-time (so I can see errors as they come in) not afterwards when I call a stored variable – Vainmonde De Courtenay Apr 19 '21 at 16:21
  • Yeh, if you need (near) real-time, you are stuck with bare `Popen`. The [Stack Overflow `subprocess` tag info page](/tags/subprocess/info) has a couple of FAQs about this. – tripleee Apr 19 '21 at 19:15