Assign Output of Os.System to a Variable and Prevent It from Being Displayed on the Screen

Assign output of os.system to a variable and prevent it from being displayed on the screen

From "Equivalent of Bash Backticks in Python", which I asked a long time ago, what you may want to use is popen:

os.popen('cat /etc/services').read()

From the docs for Python 3.6,

This is implemented using subprocess.Popen; see that class’s
documentation for more powerful ways to manage and communicate with
subprocesses.


Here's the corresponding code for subprocess:

import subprocess

proc = subprocess.Popen(["cat", "/etc/services"], stdout=subprocess.PIPE, shell=True)
(out, err) = proc.communicate()
print "program output:", out

How to store os.system() output in a variable or a list in python

There are many good SO links on this one. try Running shell command from Python and capturing the output or Assign output of os.system to a variable and prevent it from being displayed on the screen for starters. In short

import subprocess
direct_output = subprocess.check_output('ls', shell=True) #could be anything here.

The shell=True flag should be used with caution:

From the docs:
Warning

Invoking the system shell with shell=True can be a security hazard if combined with untrusted input. See the warning under Frequently Used Arguments for details.

See for much more info: http://docs.python.org/2/library/subprocess.html

Python: How to get stdout after running os.system?

If all you need is the stdout output, then take a look at subprocess.check_output():

import subprocess

batcmd="dir"
result = subprocess.check_output(batcmd, shell=True)

Because you were using os.system(), you'd have to set shell=True to get the same behaviour. You do want to heed the security concerns about passing untrusted arguments to your shell.

If you need to capture stderr as well, simply add stderr=subprocess.STDOUT to the call:

result = subprocess.check_output([batcmd], stderr=subprocess.STDOUT)

to redirect the error output to the default output stream.

If you know that the output is text, add text=True to decode the returned bytes value with the platform default encoding; use encoding="..." instead if that codec is not correct for the data you receive.

How would I store the shell command output to a variable in python?

By using module subprocess. It is included in Python's standard library and aims to be the substitute of os.system. (Note that the parameter capture_output of subprocess.run was introduced in Python 3.7)

>>> import subprocess
>>> subprocess.run(['cat', '/etc/hostname'], capture_output=True)
CompletedProcess(args=['cat', '/etc/hostname'], returncode=0, stdout='example.com\n', stderr=b'')
>>> subprocess.run(['cat', '/etc/hostname'], capture_output=True).stdout.decode()
'example.com\n'

In your case, just:

import subprocess

v = subprocess.run(['cat', '/etc/redhat-release'], capture_output=True).stdout.decode()

Update: you can split the shell command easily with shlex.split provided by the standard library.

>>> import shlex
>>> shlex.split('cat /etc/redhat-release')
['cat', '/etc/redhat-release']
>>> subprocess.run(shlex.split('cat /etc/hostname'), capture_output=True).stdout.decode()
'example.com\n'

Update 2: os.popen mentioned by @Matthias

However, is is impossible for this function to separate stdout and stderr.

import os

v = os.popen('cat /etc/redhat-release').read()

Hiding console output produced by os.system

To answer the question based on its title in the most generic form:

To suppress all output from os.system(), append >/dev/null 2>&1 to the shell command, which silences both stdout and stderr; e.g.:

import os
os.system('echo 3 | sudo tee /proc/sys/vm/drop_caches >/dev/null 2>&1')

Note that os.system() by design passes output from the calling process' stdout and stderr streams through to the console (terminal) - your Python code never sees them.

Also, os.system() does not raise an exception if the shell command fails and instead returns an exit code; note that it takes additional work to extract the shell command's true exit code: you need to extract the high byte from the 16-bit value returned, by applying >> 8 (although you can rely on a return value other than 0 implying an error condition).


Given the above limitations of os.system(), it is generally worthwhile to use the functions in the subprocess module instead:

For instance, subprocess.check_output() could be used as follows:

import subprocess
subprocess.check_output('echo 3 | sudo tee /proc/sys/vm/drop_caches', shell=True)

The above will:

  • capture stdout output and return it (with the return value being ignored in the example above)
  • pass stderr output through; passing stderr=subprocess.STDOUT as an additional argument would also capture stderr.
  • raise an error, if the shell command fails.

Note: Python 3.5 introduced subprocess.run(), a more flexible successor to both os.system() and subprocess.check_output() - see https://docs.python.org/3.5/library/subprocess.html#using-the-subprocess-module


Note:

  • The reason that the OP is employing tee in the first place - despite not being interested in stdout output - is that a naïve attempt to use > ... instead would be interpreted before sudo is invoked, and thus fail, because the required privileges to write to /proc/sys/... haven't been granted yet.
  • Whether you're using os.system() or a subprocess function, stdin is not affected by default, so if you're invoking your script from a terminal, you'll get an interactive password prompt when the sudo command is encountered (unless the credentials have been cached).

Getting output from os.system (no subprocess)

=> As Martijn Pieters says, there is no way to retrieve the stdout of a os.system() call (because it spawns a subshell = a black box of which we know nothing but its return code). The solution is then to make Python act as a proxy between the final user and CAST3M (pass-through configuration : Python is the "middleman" listening to the user request and transmitting it "as-is" to CAST3M, then capturing CAST3M answer and printing it back to the user). For this, you have to use subprocess, threading and queue modules. If you do not mind the complexity it brings (and the alteration of the original HCI experience), here is a quick summary of links which may reveal usefull :

  1. Wrap subprocess' stdout/stderr
  2. Can you make a python subprocess output stdout and stderr as usual, but also capture the output as a string?
  3. Running an interactive command from within python
  4. Non-blocking read on a subprocess.PIPE in python
  5. http://log.ooz.ie/2013/02/interactive-subprocess-communication-in.html

=> Robᵩ provides a workaround for Linux only, by appointing the logging task to the "script" Linux tool. This allows to keep the "user<>CAST3M" interactivity untouched (no proxy here).

How to store executed command (of cmd) into a variable?

Try (for Python3.7+):

import subprocess
data = subprocess.run(["tree", "D://"], capture_output=True)

For Python<3.7:

import subprocess
data = subprocess.run(["tree", "D://"], stdout=subprocess.PIPE, stderr=subprocess.PIPE)


Related Topics



Leave a reply



Submit