dspshyama
dspshyama

Reputation: 473

Write SSH command over multiple lines

I'm trying to remote login to a shell and execute a bunch of commands on the shell. But to make it more readable, I'd like to place my code over multiple lines. How should I be doing this?

ssh -o <Option> -x -l <user> <host> " $long_command1; $long_command2; ....  "

Thanks!

Upvotes: 35

Views: 40131

Answers (5)

Charles Duffy
Charles Duffy

Reputation: 295707

The answers thus far have all left out a technique that's much less issue-prone than writing code in a heredoc, quoted string, or other environment that has subtly different behavior than the outer shell: Define a function, and let bash itself serialize that function into the arguments passed to ssh.

remoteFunc() {
  long_command 1 && ...
  long_command 2...
  if blah; then long_command 3; else meh; fi

  # In a single-quoted string, these quotes would disappear!
  echo "string with 'single quotes'"

  # in a heredoc or double quotes, remoteCommand would be run locally!
  remoteCmdOutput=$(remoteCommand)
}

ssh remoteHost "$(declare -f remoteFunc); remoteFunc"

If your function requires variables to also be passed over ssh, you can use declare -p to serialize them the same way:

myVar='...whatever...'
myOtherVar='...same...'
myFunc() {
  echo "Do something with $myVar and $myOtherVar here..."
}

ssh remoteHost "$(declare -f myFunc); $(declare -p myVar myOtherVar); myFunc"

Upvotes: 1

JohnA
JohnA

Reputation: 849

This works on Ubuntu 24.04 host and server

  • runs under sudo
  • runs multiple lines
  • does not require me to enter my sudo password

Some of these came from other answers on SO and on other sites. I did have to play with those answers until it worked as I needed it:

  • your_userid: the non-sudo userid on the remote host
  • your_remote_host: the ip address or domain of the remote host
  • the file secure_sudo_pwd has the sudo password in it
my_cool_sudo_password    <= ensure there is newline after this
  • the first cat puts the sudo password into the stdin stream and the rest of your commands until "EOF"
  • invokes SSH and then cats the stdin into the next command, which is sudo su -
  • the backslash in \| in required (it's not a markdown for SO posts).
  • the prompt prevents most of the initial dump that bash does from showing up
  • note that comments in the stdin work correctly, the lines are ignored
cat secure_sudo_pwd - << EOF | ssh $your_userid@$your_remote_host cat \| sudo --prompt="" -S -- su -
hostname
whoami
# echo commented out line
hostname
whoami
echo line1
EOF

typical output:

vm-1     <= my host is a virtualbox running Ubuntu 24.04
root     <= confirms that it is running as root
root
vm-1
line1

I have checked as best as I can whether the password or content of this SSH session shows up on the host:

# on the host
cd /var/log
tail -f dmesg syslog auth.log kern.log

There were no indications of "sudo", "hostname", "whoami", or password, etc.

There was an entry in authlog showing an ssh login

Jan  7 12:55:06 vm-1 sshd[12122]: Accepted publickey for xx from 10.0.0.xx port 33698 ssh2: ED25519 SHA256:U24xx

Upvotes: 0

ntki
ntki

Reputation: 2314

You can use the Here Documents feature of bash. It is like:

ssh <remote-host> bash <<EOF
echo first command
echo second command
EOF

EOF marks the end of the input.

For further info: use man bash and search for Here Documents.

Edit: The only caveat is that using variables can be tricky, you have to escape the $ to protect them to be evaluated on the remote host rather then the local shell. Like \$HOSTNAME. Otherwise works with everything that is run from bash and uses stdin.

Upvotes: 34

Alfe
Alfe

Reputation: 59556

ssh is in fact just passing a string to the remote host. There this string is given to a shell which is supposed to interpret it (the user's login shell, which is typically something like bash). So whatever you want to execute needs to be interpretable by that remote login shell, that's the whole rule you have to stick to.

You can indeed just use newlines within the command string:

ssh alfe@sweethome "
  ls /home/alfe/whatever
  ping foreignhost
  date
  rm foobar
"

Upvotes: 53

crafter
crafter

Reputation: 6297

You can do like in the following example.

ssh -o <Option> -x -l <user> <host> '
pwd
whoami
ls
echo "$PATH"
'

Upvotes: 3

Related Questions