46

For the following command:

subprocess.call(shlex.split(
            """/usr/local/itms/bin/iTMSTransporter -m lookupMetadata 
              -apple_id %s -destination %s"""%(self.apple_id, self.destination))

It prints the entire output into the Terminal window. How would I suppress ALL output here? I tried doing subprocess.call(shlex.split(<command> > /dev/null 2&1)), but it didn't produce the required results. How would I do this here?

rypel
  • 4,686
  • 2
  • 25
  • 36
David542
  • 104,438
  • 178
  • 489
  • 842

2 Answers2

61

You can use the stdout= and stderr= parameters to subprocess.call() to direct stdout or stderr to a file descriptor of your choice. So maybe something like this:

import os

devnull = open(os.devnull, 'w')
subprocess.call(shlex.split(
    '/usr/local/itms/bin/iTMSTransporter -m lookupMetadata '
    '-apple_id %s -destination %s' % (self,apple_id, self.destination)),
  stdout=devnull, stderr=devnull)

Using subprocess.PIPE, if you're not reading from the pipe, could cause your program to block if it generates a lot of output.

Update

As @yanlend mentions in a comment, newer (3.x) versions of Python include subprocess.DEVNULL to solve this problem in a more convenient and portable fashion. In that case, the code would look like:

subprocess.call(shlex.split(
    '/usr/local/itms/bin/iTMSTransporter -m lookupMetadata '
    '-apple_id %s -destination %s' % (self,apple_id, self.destination)),
  stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
larsks
  • 277,717
  • 41
  • 399
  • 399
  • 30
    you can just use os.devnull –  Apr 20 '12 at 18:31
  • 3
    Hey look I learned something. – larsks Apr 20 '12 at 18:49
  • 8
    Using a predefined constant like this means that if the null device were something other than `/dev/null`, this would continue to work without needing to modify your code. For example, I believe this returns something different but still useful under Windows. – larsks Apr 22 '14 at 00:38
  • what is the workaround for `subprocess.run` instead of `subprocess.call`? In that case it doesn't suppress the output – stelios Jan 27 '18 at 15:10
  • You would need to tell `subprocess.run` to collect the output. See the documentation for the `stdout` and `stderr` parameters. – larsks Jan 28 '18 at 15:44
  • 2
    You can directly use `subprocess.DEVNULL` to suppress the output, no need to use os.devnull and open it. `subprocess.call(shlex.split( '/usr/local/itms/bin/iTMSTransporter -m lookupMetadata ' '-apple_id %s -destination %s' % (self,apple_id, self.destination)), stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)` see https://docs.python.org/3/library/subprocess.html#subprocess.DEVNULL – yanlend Jun 20 '18 at 07:34
6

What worked for me is appending 2>/dev/null at the end of the command.

David542
  • 104,438
  • 178
  • 489
  • 842
  • 1
    For future readers: this approach isn't guaranteed to work on all platforms/shells, even though it'll probably work on anything recent and POSIX-y. – Brighid McDonnell Jun 15 '17 at 19:37
  • 1
    (also, this only work with `shell=True`, which you want to avoid when possible) – larsks Jan 28 '18 at 15:45
  • @larsks why should I avoid `shell=true`? This solution is simple as hell and worked for my case. – d4tm4x Apr 09 '19 at 12:19
  • 1
    @month See [the docs for details](https://docs.python.org/2/library/subprocess.html#frequently-used-arguments). In addition to the security issues noted there, you can also get unexpected behavior if your command string includes any shell metacharacters, and you can also run into annoying quoting issues. – larsks Apr 09 '19 at 14:07
  • @larsks thanks! In my case, there is no vulnerability through shell injection, since my command string is not constructed but hard coded (it actually just starts a necessary docker). But I'm definitely aware of the risk, now. – d4tm4x Apr 09 '19 at 19:43
  • How? provide an example – seralouk Apr 06 '23 at 12:56