Search code examples
pythonsubprocesspipepopennetcat

Why NCat overs immediately if I call it by Popen?


I must to work with NCat stdin-pipe in my python3-script and I decided to use for this subprocess.Popen. But even I call this, NCat immediately overs with error code 2 and writes: Ncat: You must specify a host to connect to. QUITTING.. My code:

import subsubprocess
a = subprocess.Popen(['nc', '--keep-open', '--listen', '8000'], stdin = subprocess.PIPE, shell = True)
...

I tried to put localhost like penultimate argument:

a = subprocess.Popen(['nc', '--keep-open', '--listen', 'localhost', '8000'], stdin = subprocess.PIPE, shell = True)

but it gave that one result. In the console and nc --keep-open --listen 8000, and nc --keep-open --listen localhost 8000 work perfect. What should I do?


Solution

  • The problem here, I'm pretty sure, is something I came across recently. Popen doesn't do what you expect when you pass a list of arguments and specify shell = True. It's happiest when the use of these is mutually exclusive. So instead of:

    a = subprocess.Popen(['nc', '--keep-open', '--listen', '8000'], stdin = subprocess.PIPE, shell = True)
    

    I would do either:

    a = subprocess.Popen(['nc', '--keep-open', '--listen', '8000'], stdin = subprocess.PIPE)
    

    or:

    a = subprocess.Popen(['nc --keep-open --listen 8000'], stdin = subprocess.PIPE, shell = True)
    

    I did a little digging into the documentation, and I find a few interesting tidbits that confirm what I've always just kinda believed in my gut through experience:

    If shell is True, it is recommended to pass args as a string rather than as a sequence.

    On POSIX with shell=True, the shell defaults to /bin/sh. ... If args is a sequence, the first item specifies the command string, and any additional items will be treated as additional arguments to the shell itself.

    So I guess the extra arguments are being fed to /bin/sh rather than nc in your case.