Secure Shell (ssh) is the standard way to connect to a remote machine’s shell. We routinely log in and use ssh to establish an interactive session and stay logged in as long as necessary.
SSH Interactive Mode
I often need to execute a single non-interactive command on a remote host such as to check a log file or a machine’s free disk space. Obviously, that can be accomplished by establishing an interactive session, run the command, and exit as follows:
netbeez.net$ ssh pi@172.31.0.16 Linux raspberrypi 4.19.57-v7+ #1244 SMP Thu Jul 4 18:45:25 BST 2019 armv7l The programs included with the Debian GNU/Linux system are free software; the exact distribution terms for each program are described in the individual files in /usr/share/doc/*/copyright. Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent permitted by applicable law. Last login: Wed Aug 18 04:12:28 2021 from 172.29.0.13 pi@172.31.0.16:~:$ df -h Filesystem Size Used Avail Use% Mounted on /dev/root 7.3G 3.1G 3.9G 45% / devtmpfs 459M 0 459M 0% /dev tmpfs 464M 0 464M 0% /dev/shm tmpfs 464M 18M 446M 4% /run tmpfs 5.0M 4.0K 5.0M 1% /run/lock tmpfs 464M 0 464M 0% /sys/fs/cgroup /dev/mmcblk0p1 41M 23M 19M 55% /boot tmpfs 93M 0 93M 0% /run/user/1000 pi@172.31.0.16:~:$ exit logout Connection to 172.31.0.16 closed.
How to Configure SSH for Non-Interactive Mode
Here is the step-by-step process:
- Logged into the remote machine
- Executed the command
- Logged out of the remote machine
Note that I had set up passwordless ssh beforehand to avoid typing in my password every single time.
This is not too bad, but when there is a better option why not use it?
The alternative is execute the command via ssh on the remote host as follows:
netbeez.net$ ssh pi@172.31.0.16 df -h Filesystem Size Used Avail Use% Mounted on /dev/root 7.3G 3.1G 3.9G 45% / devtmpfs 459M 0 459M 0% /dev tmpfs 464M 0 464M 0% /dev/shm tmpfs 464M 18M 446M 4% /run tmpfs 5.0M 4.0K 5.0M 1% /run/lock tmpfs 464M 0 464M 0% /sys/fs/cgroup /dev/mmcblk0p1 41M 23M 19M 55% /boot tmpfs 93M 0 93M 0% /run/user/1000
As you can see I added the command df -h
after the ssh login information, the command executed on the remote machine, and the output was printed on my local shell. This may not seem like a big deal, but I personally use it very often to get the IP address assigned by my DHCP server to a machine that just connected to the network as follows:
netbeez.net$ ssh netbeez@172.31.0.1 tail /var/log/syslog Aug 17 05:24:50 utilite dhcpd: DHCPREQUEST for 172.31.0.39 from b8:27:eb:.. via eth1 Aug 17 05:24:50 utilite dhcpd: DHCPACK on 172.31.0.39 to b8:27:eb:.. via eth1 Aug 17 05:24:52 utilite dhcpd: DHCPREQUEST for 172.31.0.38 from b8:27:eb:.. via eth1 Aug 17 05:24:52 utilite dhcpd: DHCPACK on 172.31.0.38 to b8:27:eb:.. via eth1 Aug 17 05:24:54 utilite dhcpd: DHCPREQUEST for 172.31.0.243 from b8:27:eb:.. via eth1 Aug 17 05:24:54 utilite dhcpd: DHCPACK on 172.31.0.243 to b8:27:eb:.. via eth1 Aug 17 05:24:55 utilite dhcpd: DHCPREQUEST for 172.31.0.183 from b8:27:eb:.. via eth1 Aug 17 05:24:55 utilite dhcpd: DHCPACK on 172.31.0.183 to b8:27:eb:dc:f9:83 via eth1 Aug 17 05:24:57 utilite dhcpd: DHCPREQUEST for 172.31.0.21 from b8:27:eb:.. via eth1 Aug 17 05:24:57 utilite dhcpd: DHCPACK on 172.31.0.21 to b8:27:eb:.. via eth1
In this case, I know that the DHCP server logs in /var/log/syslog
all IP assignments. With the remote execution of the tail /var/log/syslog
command on the DHCP server at 172.31.0.1
I see that the last assigned IP was 172.31.0.21
. I can also see the MAC address of the machine that this IP was assigned to was b8:27:eb:..
and from there I can identify the machine that got that IP.
The other benefit of remote execution of non-interactive commands with ssh is that you can include them in scripts since the output can be parsed like any other command output. For example, here is a script that checks if the root partition of a remote host is 90% full, and if it is it prompts to delete the 10 largest files in the /var/log/ directory:
REMOTE_HOST="pi@172.31.0.16" DISK_LIMIT=90 PARTITION="/" CLEANUP_DIR="/var/log/" if [ "$(ssh ${REMOTE_HOST} df ${PARTITION} | grep ${PARTITION} \\ | awk '{print $5}' | tr -d %)" -gt "${DISK_LIMIT}" ]; then echo "Remote host dist utilization greater than ${DISK_LIMIT}%" echo "Cleaning up 10 largest log files" for file in $(ssh ${REMOTE_HOST} ls -S ${CLEANUP_DIR}/ | head); do read -p "Should I clean ${CLEANUP_DIR}/$(ls -la ${CLEANUP_DIR}/${file})?" -n 1 -r echo if [[ ${REPLY} =~ ^[Yy]$ ]] then echo "Deleting ${REMOTE_HOST}:${CLEANUP_DIR}/${file}" ssh ${REMOTE_HOST} rm ${CLEANUP_DIR}/${file} fi done fi
Conclusion
This is just a pointer to the remote command execution with ssh and just a few examples of how I use this as part of my daily Linux administration tasks. Drop me a line in the comments if you find any good use cases of this as well.