1

I am executing program which connects to external server from python.
If user is not authenticated, the program asks for username and password.

Here is how subprogram output looks:

Authentication Required

Enter authorization information for "Web API"

<username_prompt_here>
<password_prompt_here>

I want to kill subprocess right after 'Authentication Required' is printed, but the problem is, that my code works wrong - subprocess is asking for credentials and after user provides it, the subprocess is killed.

Here is my code:

with subprocess.Popen(self.command, stdout=subprocess.PIPE, shell=True, bufsize=1, universal_newlines=True) as process:
    for line in process.stdout:
        if 'Authentication Required' in line:
            print('No authentication')
            process.kill()
        print(line)

What am I doing wrong?

usamazf
  • 3,195
  • 4
  • 22
  • 40
Djent
  • 2,877
  • 10
  • 41
  • 66
  • Can you post the complete code? or is it complete? I don't see where you are prompting user for username and password. – usamazf Feb 19 '16 at 06:31
  • I'm not prompting - the subprogram does it (look at attatched output). – Djent Feb 19 '16 at 06:37
  • and you want to kill the process immediatly after Authentication Required line? – usamazf Feb 19 '16 at 06:39
  • does it actually wait for the user to enter username and password beforing exiting the sub routine? – usamazf Feb 19 '16 at 06:40
  • Yes, I don't want to let subprogram ask for password, in current situation is asking for it, and after that is killed. – Djent Feb 19 '16 at 06:41
  • And - not always I want to kill program after first line. Only if first line is 'Authentication required'. – Djent Feb 19 '16 at 06:42
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/103923/discussion-between-usama-zafar-and-djent). – usamazf Feb 19 '16 at 06:43

1 Answers1

2

What am I doing wrong?

Your code is ok (if you want to kill the subprocess after 'Authentication Required' line regardless its position) if the child process flushes its stdout buffer in time. See Python: read streaming input from subprocess.communicate()

The observed behavior indicates that the child uses a block-buffering mode and therefore your parent script sees the 'Authentication Required' line too late or that killing the shell with process.kill() doesn't kill its descendants (processes created by the command).

To workaround it:

  • See whether you could pass a command-line argument such as --line-buffered (accepted by grep), to force a line-buffered mode
  • Or see whether stdbuf, unbuffer, script utilities work in your case
  • Or provide a pseudo-tty to hoodwink the process into thinking that it runs in a terminal directly — it may also force the line-buffered mode.

See code examples in:


And - not always I want to kill program after first line. Only if first line is 'Authentication required'

Assuming the block-buffering issue is fixed, to kill the child process if the first line contains Authentication Required:

with Popen(shlex.split(command), 
           stdout=PIPE, bufsize=1, universal_newlines=True) as process:
    first_line = next(process.stdout)
    if 'Authentication Required' in first_line:
        process.kill()
    else: # whatever
        print(first_line, end='')
        for line in process.stdout:
            print(line, end='')

If shell=True is necessary in your case then see How to terminate a python subprocess launched with shell=True.

Community
  • 1
  • 1
jfs
  • 399,953
  • 195
  • 994
  • 1,670