On 29May2019 22:37, Fc Zwtyds <fczwt...@gmail.com> wrote:
在 2019-05-27 11:19, Cameron Simpson 写道:
The output of "ssh-agent -s" is Bourne shell variable assignment
syntax. You need to parse that [...]
I want to rewrite the shell script to python script so I have had
changed the "ssh-agent -s" to 'ssh-agent cmd' in python script for the
consistence on windows.
I'm not sure you need to do that. In fact, I'm fairly sure you don't.
When you run "ssh-agent cmd" the agent starts as before, but instead of
reporting its communication socket and process id it dispatches command
and runs for the duration of that command, then exits.
Before ssh-agent dispatches "cmd" (here I mean a generic command, though
that command might well be "cmd.exe"), it first puts the necessary
environment variables into the command's environment.
There are two such values: the communication socket and the ssh-agent
process id. The socket is so that the other ssh commands can talk to it,
and the process id is so that it can be terminated when no longer
wanted. For the "ssh-agent cmd" form there's no need to use the process
id, since ssh-agent itself will exit after "cmd" finishes.
Let's look at what "ssh-agent -s" produces. This is on a UNIX system (my
Mac):
[~]fleet*> ssh-agent -s
SSH_AUTH_SOCK=/Users/cameron/tmp/ssh-vuvXU6vrCAxz/agent.50746; export
SSH_AUTH_SOCK;
SSH_AGENT_PID=50754; export SSH_AGENT_PID;
echo Agent pid 50754;
You can see the socket path and the process id there. The paths will be
a bit different on Windows.
So if I do a process listing (this is a UNIX "ps" command, you will need
to do the equivalent Windows thing) and search for that process id we
see:
[~]fleet*1> ps ax | grep 62928
62928 ?? Ss 0:00.00 ssh-agent -s
66204 s027 S+ 0:00.00 grep 62928
So there's the ssh-agent process and also the "grep" command itself
because the process id is present on its command line.
Note that at this point my shell (cmd.exe equivalent in Windows) does
not know about the new ssh-agent. This is because I haven't put those
environment values into the shell environment: the output above is just
written to the display. So when I go:
[~]fleet*> ssh-add -l
it shows me 4 ssh keys. This is because I already have an agent which
has some keys loaded. If my shell were talking to the new agent the list
would be empty. Let's do that.
[~]fleet*> SSH_AUTH_SOCK=/Users/cameron/tmp/ssh-vuvXU6vrCAxz/agent.50746
[~]fleet*> SSH_AGENT_PID=50754
[~]fleet*> export SSH_AUTH_SOCK SSH_AGENT_PID
[~]fleet*> ssh-add -l
The agent has no identities.
So now this shell is using the new agent. You see there's no magic here:
other commands do not know about the agent until we tell then about it
using these environment variables.
What I was suggesting is that you perform this process from Python,
which I believe was your original plan.
So let's adapt the the comand you presented below, and also dig into why
what you've tried hasn't worked. So, your subprocess call:
import subprocess
p = subprocess.Popen('cmd', stdin = subprocess.PIPE, stdout = subprocess.PIPE,
stderr = subprocess.PIPE, shell = True, universal_newlines = True)
outinfo, errinfo = p.communicate('ssh-agent cmd\n')
print('outinfo is \n %s' % stdoutinfo)
print('errinfo is \n %s' % stderrinfo)
This does the follow things:
1: Start a subprocess running "cmd". You get back a Popen object "p" for
use with that process.
2: Run p.communicate("ssh-agent cmd\n"). This sends that to the input of
the "cmd" subprocess and collects the output.
An important thing to know here is the .communicate is a complete
interaction with the subprocess. The subprocess' _entire_ input is the
string you've supplied, and the entire output of the subprocess until it
completes is collected.
So, what's going on is this:
1: start "cmd"
2: send "ssh-agent cmd\n" to it.
3: collect output and wait for it to exit.
From "cmd"'s point of view:
1: Receive "ssh-agent cmd\n", causing it to run the "ssh-=agent cmd"
command and then wait for it to exit.
2: ssh-agent starts and then runs another "cmd" and waits for _that_ to
exit.
3: The second "cmd" processes its input, then exits. Note that becuase
the input to the entire subprocess was "ssh-agent cmd\n", and the first
"cmd" consumed that, there is no no more input data. So the second cmd
exits immediately because there is no input.
4: The ssh-agent exist because the second "cmd" exited.
5: The first "cmd" sees the "ssh-agent cmd" command exit and looks for
another command to run from its input.
6: As before, there are no more input data. So the first "cmd" also
exits.
And at that point .communicate sees the end of the output and returns
it.
Because the subprocess is complete, your commented out "p.write" call
fails. You can't do things that way with .communicate.
There are complicated (and error prone) ways to do more incremental
input, not using .communicate. Let us not go there for now.
Instead, let's consider using communicate with your original plan, which
was to reproduce a script when went:
ssh-agent -s
ssh-add id_rsa
... more ssh based commands here ...
You were using os.system(), which just dispatches a command and doesn't
do anything about its input or output. We want to use .communicate
because it lets us collect the agent information.
The important thing to note here is that the _only_ extra information
the commands after "ssh-agent" require is the environment variables.
So you can go:
1: Dispatch "ssh-agent -s" with subprocess and use .communicate to
collect the output.
2: Parse the environment values out of the output and install them in
Python's os.environ dictionary.
3: Run your other ssh commands. because os.environ has the necessary
values in it, they will communicate with the agent, which is still
sitting around.
4: When finished, kill the agent to tidy up.
So start with this:
p = subprocess.Popen('ssh-agent -s', stdin = subprocess.PIPE, stdout =
subprocess.PIPE, stderr = subprocess.PIPE, shell = True, universal_newlines =
True)
outinfo, errinfo = p.communicate('ssh-agent cmd\n')
You should get the output from ssh-agent in "outinfo". Remember, it is a
single string looking like this:
SSH_AUTH_SOCK=/Users/cameron/tmp/ssh-vuvXU6vrCAxz/agent.50746; export
SSH_AUTH_SOCK;
SSH_AGENT_PID=50754; export SSH_AGENT_PID;
echo Agent pid 50754;
Obviously the specific paths and numbers will vary.
So you want to parse that. Untested code:
import os
# break the output data into lines
lines = outinfo.split('\n')
for line in lines:
# trim leading and trailing whitespace
line = line.strip()
# ignore blank/empty lines
if not line:
continue
# break off the part before the semicolon
left, right = line.split(';', 1)
if '=' in left:
# get variable and value, put into os.environ
varname, varvalue = left.split('=', 1)
print("got", varname, "=', "varvalue)
os.environ[varname]=varvalue
The you could just use os.system() to run the other commands, because
the environment now has the necessary environment settings.
See how you go.
Cheers,
Cameron Simpson <c...@cskk.id.au> (formerly c...@zip.com.au)
--
https://mail.python.org/mailman/listinfo/python-list