Reputation: 3467
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?
Upvotes: 1
Views: 656
Reputation: 414255
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:
--line-buffered
(accepted by grep
), to force a line-buffered modestdbuf
, unbuffer
, script
utilities work in your caseSee 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.
Upvotes: 2