At least part of the problem is that the local shell (invoked by shell=True
) is processing the command before it's sent to the remote system, so the ;
in the command string is treated as a command delimiter on the local system (and the part after ;
executes locally rather than being sent to the remote system). If the actual command is more complex, it may be doing other unwanted parsing (e.g. replacing $variable
in the command with the local value of that variable).
At least in the example in the question, the local shell isn't doing anything useful, so one solution is to use shell=True
. There is one other change, though: rather than passing the command as a single string, you need to pass it as a list of words, like ["ssh", f"user@{ip}", cmds]
:
output, errors = subprocess.Popen(["ssh", f"user@{ip}", cmds], shell=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()
Avoiding expanding $variable
references locally might solve the environment variable problems you're having; if not, you'd have to explain how you're defining and using the variables in question.