11"""This package provides SSH function.
22"""
3- import shlex
43import os
54from ptrlib .os import which
65from .proc import Process
@@ -10,11 +9,11 @@ def SSH(host: str,
109 username : str ,
1110 * ,
1211 port : int = 22 ,
13- password : str | None = None ,
14- identity : str | None = None ,
15- ssh_path : str | None = None ,
12+ password : str | None = None ,
13+ identity : str | None = None ,
14+ ssh_path : str | None = None ,
1615 options : list [str ] | None = None ,
17- command : str = '' ):
16+ command : str | None = None ):
1817 """Create an SSH shell
1918
2019 Create a new process to connect to SSH server
@@ -35,8 +34,7 @@ def SSH(host: str,
3534 FileNotFoundError: If SSH executable is not found.
3635 """
3736 assert isinstance (port , int )
38- if identity is None and password is None :
39- raise ValueError ("You must provide either password or identity" )
37+ # Allow agent-based auth when neither password nor identity is provided.
4038 if ssh_path is None :
4139 ssh_path = which ('ssh' )
4240 if ssh_path is None or not os .path .isfile (ssh_path ):
@@ -47,14 +45,19 @@ def SSH(host: str,
4745 if identity is not None :
4846 options += ['-i' , os .path .realpath (os .path .expanduser (identity ))]
4947
50- sess = Process ( [
48+ argv : list [ str ] = [
5149 ssh_path ,
5250 '-oStrictHostKeyChecking=no' , '-oCheckHostIP=no' ,
53- f'{ shlex . quote ( username ) } @{ shlex . quote ( host ) } ' ,
51+ f'{ username } @{ host } ' ,
5452 '-p' , str (port ),
5553 * options ,
56- command
57- ])
54+ ]
55+ # Only append command if provided (avoid passing an empty argument which
56+ # would make ssh execute an empty remote command and close immediately).
57+ if command :
58+ argv .append (command )
59+
60+ sess = Process (argv )
5861 sess .prompt = ""
5962 if password is not None :
6063 sess .sendlineafter ("password: " , password )
0 commit comments