How To Execute Shell Commands Over SSH Using Python?

July 25, 2022

A prevalent task when automating the boring stuff in Python is to run shell commands. If you are working with servers or virtual machines, you'd also need to run commands on a remote computer.

You can use the standard Python module and subprocesses to run shell scripts. It's an easy way to execute commands. But on remote computers, you may need other techniques.

This post walks you through executing raw shell scripts using ssh. Then we'll also discuss more Pythonic ways to run scripts on remote computers.

Running SSH commands using the subprocess module.

The subprocess module needs no further installation. It's a standard Python library. Hence, you can use the ssh command line utility inside your subprocess run method.

The following command will run the Linux shell and get the free memory information of a remote computer. When running this script, the system will ask you to type in your password.

Note that the subprocess run command takes a list of arguments, not a string. But you can also use iterable such as a tuple or a set in place of a list.

import subprocess

subprocess.run(("ssh", "<REMOTE UNAME>@<REMOTE IP/HOSTNAME>", "free", "-m"))
total        used        free      shared  buff/cache   available
Mem:           1985         583         165          31        1235        1186
Swap:             0           0           0

Copy files from and to remote computers

In the same way, we can use the subprocess module to copy files from and to remote computers. The following python script is an example of copying local files to a remote location using SCP.

This script uses argparser to get remote and local file paths as command line arguments.

import subprocess
import argparse
import pathlib

parser = argparse.ArgumentParser()

parser.add_argument("-l", "--local-path", required=True, type=pathlib.Path)
parser.add_argument("-r", "--remote-path", required=True, type=pathlib.Path)


args = parser.parse_args()

# Copy the file to the remote path
command = ["scp", args.local_path, f"<REMOTE_UNAME>@<REMOTE_HOSTNAME/IP>:{args.remote_path}"]


subprocess.run(command)
$ python copy_file.py -l sample.txt -r /home/ubuntu/
sample.txt                                                                            100%   58     0.1KB/s   00:00

Passwordless ssh in Python

You'd have noticed that the ssh utility keeps asking for passwords every time you try to run a command on the remote computer. You can avoid this in two ways.

One is to embed passwords in the command itself. If you intend to share your code with others, you can set up an environment variable instead of hardcoding.

The second option is to set up an ssh key and add it to the remote computer's authorized keys.

Embedded password in the ssh command

Before using this option, here's a warning. I don't recommend using passwords in any shell command. That's because shell history will store the command along with your passwords. Also, the password is exposed to other processes running on the computer.

We need to use the sshpass utility with ssh to use passwords in the same command.

The shell command below will run on a remote computer without prompting for a password. You can replace the `free -m` with any valid Unix command.

sshpass -p <YOURPASSWORD> ssh <USERNAME>@<HOST_NAME> free -m

In our Python code, we can do this little tweak to embed password shell commands.

import os
import subprocess

command = [
    "sshpass",
    "-p",
    os.environ["PASSWORD"], # Assuming the password is provided through an env variable.
    "ssh",
    os.environ["USERNAME"] + "@" + os.environ["HOSTNAME"],
    "free -m",
]

subprocess.run(command)

Use SSH Keys to avoid passwords (Recommended)

Key files are the most stable way to connect through ssh. We generate an ssh key in our local computer and let the remote computer know about it. Generating key files creates two of them. One of them is the public key. It has an extension, `pub`. This is the key you should share with the remote computer, not the private one (with no extension).

The following steps will create an ssh key in Linux systems and copy it to a remote server. If you're using Windows or Mac, follow the respective instructions.

ssh-keygen
# Follow the on-screen instructions. You can also press enter to accept the default values

evan $(ssh-agent)

ssh-add ~/.ssh/id_rsa

ssh-copy-id -i ~/.ssh/id_rsa.pub <USERNAME>@<HOSTNAME>

You might have to enter your password once (and for all) to copy the ssh key to the server. But on all subsequent ssh commands, you don't have to worry about passwords or security.

Edit SSH Config file for convenient server communications.

In Linux systems, you can also create an ssh config file. In the config file, you can specify a name for the connection and other parameters. This way, you don't even have to remember the hostname or the username.

If you also followed the keyfile convention, you don't have to worry about passwords either.

SSH Config files live inside the .ssh folder of your home directory (~/.ssh/config), and it has no file extension. The following is an example of the content for SSH Config files.

Host prod
        HostName 3.231.56.176
        User ubuntu

Host dev
        HostName 54.232.237.63
        User ubuntu

Once you have the ssh config setup, you can run remote shell commands with just the hostname.

ssh prod free -m

The methods we've discussed in this section aren't largely impacted our Python script. Yet, the code is more clear and more secure now.

How we work

Readers support The Analytics Club. We earn through display ads. Also, when you buy something we recommend, we may get an affiliate commission. But it never affects your price or what we pick.

Connect with us