-2

I can't figure out how to close a bash shell that was started via Popen. I'm on windows, and trying to automate some ssh stuff. This is much easier to do via the bash shell that comes with git, and so I'm invoking it via Popen in the following manner:

p = Popen('"my/windows/path/to/bash.exe" | git clone or other commands') 
p.wait() 

The problem is that after bash runs the commands I pipe into it, it doesn't close. It stays open causing my wait to block indefinitely.

I've tried stringing an "exit" command at the end, but it doesn't work.

p = Popen('"my/windows/path/to/bash.exe" | git clone or other commands && exit') 
p.wait() 

But still, infinite blocking on the wait. After it finishes its task, it just sits at a bash prompt doing nothing. How do I force it to close?

jfs
  • 399,953
  • 195
  • 994
  • 1,670
user3308774
  • 1,354
  • 4
  • 16
  • 20
  • 1
    What's with the `|` character here? That's not how you pass commands to bash. – Charles Duffy Feb 16 '15 at 00:45
  • 1
    Also, why are you invoking bash at all, rather than *directly* invoking your git commands from Python? The direct route makes signal handling easier -- meaning you can easily check the status of or kill the git command itself, rather than only having a handle on the bash shell and not being able to tell what git (or other subprocesses under it) is doing. – Charles Duffy Feb 16 '15 at 00:46
  • @CharlesDuffy it is how you pipe commands in bash – Calum Feb 16 '15 at 00:46
  • Popen(['/path/to/bash.exe', '-c', 'command; command; command'] – Charles Duffy Feb 16 '15 at 00:47
  • 4
    Yes, it's how you set up a pipeline in bash, but you don't run a command inside a shell by piping output from the shell into that command. `bash | git clone` takes the output of `bash` and sends that as the input of `git clone`, but `git clone` doesn't read from stdin, and bash will just sit waiting for input in that usage, which is why you get the behavior (of 'wait()' never exiting) you complain about here. – Charles Duffy Feb 16 '15 at 00:47
  • Also, according to my research, `os.Popen` passes the command to `cmd.exe`, which will be processing the pipe and the ampersands, so Bash won't even see them. – Harry Johnston Feb 16 '15 at 02:46
  • (also, `&& exit` at the end of a compound command has absolutely no effect; exiting would happen whether or not the other commands succeeded, and without any change in exit code either). – Charles Duffy Feb 16 '15 at 06:10

2 Answers2

1

Try Popen.terminate() this might help kill your process. If you have only synchronous executing commands try to use it directly with subprocess.call().

for example

import subprocess
subprocess.call(["c:\\program files (x86)\\git\\bin\\git.exe",
                     "clone",
                     "repository",
                     "c:\\repository"])
0

Following is an example of using a pipe but this is a little overcomplicated for most use cases and makes sense only if you talk with a service that needs interaction (at least in my opinion).

p = subprocess.Popen(["c:\\program files (x86)\\git\\bin\\git.exe", 
                      "clone",
                      "repository",
                      "c:\\repository"],
                      stdout=subprocess.PIPE,
                      stderr=subprocess.PIPE
                     )
print p.stderr.read()
fatal: destination path 'c:\repository' already exists and is not an empty directory.
print p.wait(
128

This can be applied to ssh as well

ersteller
  • 71
  • 4
  • `p.terminate()` would help, yes, but given the usage shown here one can also address _why_ the commands are always hanging. `subprocess.call()`, by contrast, will always hang if `p.wait()` does. – Charles Duffy Feb 16 '15 at 00:54
0

To kill the process tree, you could use taskkill command on Windows:

Popen("TASKKILL /F /PID {pid} /T".format(pid=p.pid))

As @Charles Duffy said, your bash usage is incorrect.

To run a command using bash, use -c parameter:

p = Popen([r'c:\path\to\bash.exe', '-c', 'git clone repo'])

In simple cases, you could use subprocess.check_call instead of Popen().wait():

import subprocess

subprocess.check_call([r'c:\path\to\bash.exe', '-c', 'git clone repo'])

The latter command raises an exception if bash process returns non-zero status (it indicates an error).

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