Send Remote Commands Via SSH

This is one of those “I’m posting it so I remember, ’cause I keep forgetting” posts. It’s also astoundingly cool, though, if you didn’t know about it. Which I didn’t until fairly recently.

If you’ve ever wanted to send a command to a remote computer without ever actually logging in to that computer, ssh is your friend. Yes, with ssh you can send commands directly to another system. Who knew?

I’ll keep this short and sweet. Here are some examples.

The basic form looks something like this:

ssh systemsboy@rhost.systemsboy.edu 'ls -l'

where “systemsboy” is actually your username on the remote host, and “rhost.systemsboy.edu” is your remote system. The command you’re sending is contained in single quotes.

Here is an example sending multiple commands:

ssh systemsboy@rhost.systemsboy.edu 'ls -l; ps -aux; whoami'

wherein each command is separated by a semicolon.

Finally, here is an example sending a command that requires user interaction:

ssh -t systemsboy@rhost.systemsboy.edu 'top'

Note the -t flag. That tells ssh that you’ll be interacting with remote shell. Without the -t flag top will return results after which ssh will log you out of the remote host immediately. With the -t flag, ssh keeps you logged in until you exit the interactive command. The -t flag can be used with most interactive commands, including text editors like pico and vi.

Sending remote commands via ssh is incredibly handy when writing shell scripts as it allows you to run your scripts locally even if those scripts are meant to effect changes on a remote machine. I just wrote a script, for instance, that sets up vacation mail forwarding for staff members. Without these remote commands I would have had to have staff members log directly onto the mail server and run the scripts from the command line, which I don’t think they’d be too happy about. With ssh remote commands, I can give them the scripts and they can run them right from their Desktops. Believe me, they much prefer this.

Credit where due, all information was obtained from Rambo’s post. Rambo, thanks. Whoever you are.

UPDATE:
For additional information about using this trick with variables within the remote command, see “Using SSH to Send Variables in Scripts.”

18 Comments

  1. matx
    Posted July 20, 2006 at 9:35 PM | Permalink

    I’ve been using SSH for years and I never knew about this feature until this January when I attended the Macworld Expo IT conference. This is one coolest things I’ve ever heard of. (Almost as cool as electric cars!) And I can’t believe no one really has talked about it. It’s just so darn freaking cool. And like you said works well for those scripts to have other users execute what you’ve prepared for them.

  2. matx
    Posted July 21, 2006 at 9:24 PM | Permalink

    I think I found the origin of that info that “Rambo” sourced. It’s half in German and half in English, but all good stuff.

    http://www.akadia.com/services/unix_tools.html

  3. systemsboy
    Posted July 21, 2006 at 11:10 PM | Permalink

    Ach! Nein! I can’t read those pages! (Well, most of them anyway.)

    I’m glad I’m not the only one who was unaware of this SSH superpower. Maybe it’s just one of those things everyone already knows. But man is it handy!

    -systemsboy

  4. ashley
    Posted November 14, 2006 at 6:05 PM | Permalink

    Here you have some info about how to set up the ssh connection using keys with restrictions:

    command=”/path/to/ilium/rdistd -S” NNNN MM 89012[bulk still gone for the sake of example]34567 priam@sparta

    so that only a certain command be called while using this key. very neat.

  5. systemsboy
    Posted November 14, 2006 at 6:08 PM | Permalink

    Ashley,

    Excellent! Thank you!

    -systemboy

  6. linux_newbie8478
    Posted December 6, 2007 at 1:29 AM | Permalink

    Hi,

    I’m writing a small python script, which should ssh to 5 diff boxes and get the result for uptime from each box. I want to run this as a daemon process so that I know the least loaded box at any time.

    This can be easily done using a simple for loop around -
    load = str(commands.getoutput(“ssh ” + machine[0]+ ” uptime”))

    But the problem arises when 1 of the 5 remote machines is down. The script just waits for a response from that machine and does not move on to the next box

    How do I instruct the ssh cmd to timeout after say 1 min?

    This can be achieved using a Timer thread in the python script, but it would be much easier if ssh had a switch for the same.

    Unfortunately I can’t locate anything in the man pages for ssh

    BTW I’m using -
    $ ssh -V
    OpenSSH_3.6.1p2, SSH protocols 1.5/2.0, OpenSSL 0x0090701f
    $

    Thanks for your help

  7. kernalpanx
    Posted January 23, 2008 at 8:42 PM | Permalink

    when u have more then one server to do that too…… with a good naming convention you can laways use the for command
    for i in 1 2 3 4 5 6 7 8 9 10 11 ; do ssh admin@fileserver$i.domain.com ‘date’ ‘cd / ; du -sh /* ; done

    etc etc

  8. systemsboy
    Posted January 23, 2008 at 8:51 PM | Permalink

    Yup. Nothing like a good ol’ for loop. You could do similar with a simple list of computer names:
    for computer in `cat computers.txt`; do ssh -t user@$computer.domain ‘ls /Applications’; done

    Love it!

    -systemsboy

  9. Razi
    Posted June 27, 2008 at 5:22 AM | Permalink

    How do I accomplish the same task but after I terminate the command, I want to remain logged into the terminal?

  10. systemsboy
    Posted July 1, 2008 at 11:53 PM | Permalink

    Razi,

    The end of the command should not log you out of the Terminal. It should only log you out of the machine you’re SSHing to. If you don’t want to log out of that machine, there’s not really any reason to use this method. Just SSH into the machine and run your command(s). Then log out when you’re good and ready.

    Or, to answer your question more directly, I don’t know of a way to do this, but I don’t really know why you’d need to either.

    -systemsboy

  11. Tim
    Posted July 30, 2008 at 10:00 PM | Permalink

    With openssh you can set a ConnectTimeout…
    ssh -o ConnectTimeout=8 blah blah

    Timeout is in seconds.

  12. Jussi
    Posted May 3, 2010 at 3:55 AM | Permalink

    @systemsboy and @Razi:
    One scenario where you would like to have behaviour like described is when you would like to attach to a remote screen automatically (with for example “screen -dr”) but would also like to later detach the screen to be able to do something else on the server.

    If the run command is only “screen -dr” the detaching from the screen session would also log you out. Ouch. I personally use “screen -dr && bash -i” as the command to run. It’s not the most beautiful approach but seems to work.

    Why do I want it? I run screen+irssi on a remote server. Whenever my internet connection breaks for long enough time for the ssh session to break, I want to be able to reconnect and be ready for IRC business as soon as possible with as little hassle as possible :)

  13. davessh -p 8222 smtp1.sound-i.co.uk 'screen -rd'
    Posted May 24, 2010 at 1:26 PM | Permalink

    silky, i use the -t to reattach my screen session once ssh has connected (using keyless logins). Moist, now i can run one command, connect to my chat server and reattach my screen so my irc stays connected permantly. Nice!!

  14. Butch
    Posted August 14, 2011 at 9:28 AM | Permalink

    @linux_newbie8478

    On the note of the ssh timeout, you could precede every command with a netcat sequence to see if the host is accessible. Something like:
    nc -z hostname 22 -w 2

    If you get the string “Success!” the server is up and accepting connections on port 22, the return code will (should) be 0. If the server doesn’t respond it will time out after 2 seconds and the return code will (should) be 1.

    Maybe use an if statement inside your for loop? (example is written in BASH)
    for i in ${serverList[@]};
    do
    nc -z -w 2 $i 22;
    if [ $? == 0 ];
    then ssh $i ‘uptime’ >> uptime.log;
    else echo “Host is down” >> error.log;
    fi
    done

    This will almost do what it looks like you wanted. Adapting it for Python shouldn’t be difficult, but I did it with BASH as that is what I’m most fluent with. It needs some clean up for things like hostnames in the uptime and error logs and such, but should help provide some direction.

    Also if you setup ssh keys then you wont have to worry about entering the password every time.

  15. surendra
    Posted August 30, 2011 at 7:31 AM | Permalink

    hi this is surendra

    i have ssh ftp configure

    in my server one user is there

    /home/services/DAILY
    how can i put path
    linux centos5

    # $OpenBSD: sshd_config,v 1.73 2005/12/06 22:38:28 reyk Exp $

    # This is the sshd server system-wide configuration file. See
    # sshd_config(5) for more information.

    #PATH=/home/services/DAILY

    # The strategy used for options in the default sshd_config shipped with
    # OpenSSH is to specify options with their default value where
    # possible, but leave them commented. Uncommented options change a
    # default value.

    #Port 22
    #Protocol 2,1
    Protocol 2
    #AddressFamily any
    #ListenAddress 0.0.0.0
    #ListenAddress ::

    # HostKey for protocol version 1
    #HostKey /etc/ssh/ssh_host_key
    # HostKeys for protocol version 2
    #HostKey /etc/ssh/ssh_host_rsa_key
    #HostKey /etc/ssh/ssh_host_dsa_key

    # Lifetime and size of ephemeral version 1 server key
    #KeyRegenerationInterval 1h
    #ServerKeyBits 768

    # Logging
    # obsoletes QuietMode and FascistLogging
    #SyslogFacility AUTH
    SyslogFacility AUTHPRIV
    #LogLevel INFO

    # Authentication:

    #LoginGraceTime 2m
    #PermitRootLogin yes
    #StrictModes yes
    #MaxAuthTries 6

    #RSAAuthentication yes
    #PubkeyAuthentication yes
    #AuthorizedKeysFile .ssh/authorized_keys

    # For this to work you will also need host keys in /etc/ssh/ssh_known_hosts
    #RhostsRSAAuthentication no
    # similar for protocol version 2
    #HostbasedAuthentication no
    # Change to yes if you don’t trust ~/.ssh/known_hosts for
    # RhostsRSAAuthentication and HostbasedAuthentication
    #IgnoreUserKnownHosts no
    #59.90.131.411
    # Don’t read the user’s ~/.rhosts and ~/.shosts files
    #IgnoreRhosts yes

    # To disable tunneled clear text passwords, change to no here!
    #PasswordAuthentication yes
    #PermitEmptyPasswords no
    PasswordAuthentication yes

    # Change to no to disable s/key passwords
    #ChallengeResponseAuthentication yes
    ChallengeResponseAuthentication no

    # Kerberos options
    #KerberosAuthentication no
    #KerberosOrLocalPasswd yes
    #KerberosTicketCleanup yes
    #KerberosGetAFSToken no

    # GSSAPI options
    #GSSAPIAuthentication no
    GSSAPIAuthentication yes
    #GSSAPICleanupCredentials yes
    GSSAPICleanupCredentials yes

    # Set this to ‘yes’ to enable PAM authentication, account processing,
    # and session processing. If this is enabled, PAM authentication will
    # be allowed through the ChallengeResponseAuthentication mechanism.
    # Depending on your PAM configuration, this may bypass the setting of
    # PasswordAuthentication, PermitEmptyPasswords, and
    # “PermitRootLogin without-password”. If you just want the PAM account and
    # session checks to run without PAM authentication, then enable this but set
    # ChallengeResponseAuthentication=no
    #UsePAM no
    UsePAM yes

    # Accept locale-related environment variables
    AcceptEnv LANG LC_CTYPE LC_NUMERIC LC_TIME LC_COLLATE LC_MONETARY LC_MESSAGES
    AcceptEnv LC_PAPER LC_NAME LC_ADDRESS LC_TELEPHONE LC_MEASUREMENT
    AcceptEnv LC_IDENTIFICATION LC_ALL
    #AllowTcpForwarding yes
    #GatewayPorts no
    #X11Forwarding no
    X11Forwarding yes
    #X11DisplayOffset 10
    #X11UseLocalhost yes
    #PrintMotd yes
    #PrintLastLog yes
    #TCPKeepAlive yes
    #UseLogin no
    #UsePrivilegeSeparation yes
    #PermitUserEnvironment no
    #Compression delayed
    #ClientAliveInterval 0
    #ClientAliveCountMax 3
    #ShowPatchLevel no
    #UseDNS yes
    #PidFile /var/run/sshd.pid
    #MaxStartups 10
    #PermitTunnel no
    #ChrootDirectory none

    # no default banner path
    Banner /home/services/DAILY

    # override default of no subsystems
    Subsystem sftp /usr/libexec/openssh/sftp-server

  16. Posted August 30, 2011 at 8:44 AM | Permalink

    Not exactly sure what you want to do, surendra. Can you give me more information? What path are you trying to change? What are you ultimately trying to achieve?

    You are showing me the sshd_config file, which is for configuring the SSH daemon, not user properties.

    If you want to change the user’s home directory, you’d do that in /etc/passwd, I believe (Linux experts correct me if I’m wrong).

    -systemsboy

  17. Mike
    Posted November 25, 2011 at 8:25 AM | Permalink

    Hi i tried this command as …
    ssh username@ip ls … it says ls not found
    if i login using ssh and then type ls it works … also if i try it with root as in
    ssh root@ip ls it works fine …. Can anyone tell me if any configuration or permission needs to be added in order to make a user work

    thanks in advance

  18. Posted November 25, 2011 at 2:55 PM | Permalink

    I’m unable to replicate the behavior you’re describing, from a Mac SSHing to multiple clients both Mac and Linux. It sounds like the user is set up correctly, but you might check the user’s environment settings on the remote machine.

    You could also take a look at the SSH config. There are two files to check:
    /etc/ssh_config
    /etc/sshd_config

    Look for anything in those files that might be preventing standard (non-root) users from issuing remote commands or that might mess with command paths.

    FYI, I’m using the standard settings with no modifications.

    Also:
    man ssh
    man ssh_config
    man sshd_config

    Might provide clues.

    -systemsboy

One Trackback

  1. [...] you can pass the -t flag to ssh. I didn’t know this before, I found out today while reading systemsboy’s [...]

Post a Comment

Your email is never shared. Required fields are marked *

*
*