How to execute a remote command over ssh with arguments?

LinuxBashSsh

Linux Problem Overview


In my .bashrc I define a function which I can use on the command line later:

function mycommand() {
    ssh [email protected] cd testdir;./test.sh "$1"
}

When using this command, just the cd command is executed on the remote host; the test.sh command is executed on the local host. This is because the semicolon separates two different commands: the ssh command and the test.sh command.

I tried defining the function as follows (note the single quotes):

function mycommand() {
    ssh user@123.456.789.0 'cd testdir;./test.sh "$1"'
}

I tried to keep the cd command and the test.sh command together, but the argument $1 is not resolved, independent of what I give to the function. It is always tried to execute a command

./test.sh $1

on the remote host.

How do I properly define mycommand, so the script test.sh is executed on the remote host after changing into the directory testdir, with the ability to pass on the argument given to mycommand to test.sh?

Linux Solutions


Solution 1 - Linux

Do it this way instead:

function mycommand {
    ssh user@123.456.789.0 "cd testdir;./test.sh \"$1\""
}

You still have to pass the whole command as a single string, yet in that single string you need to have $1 expanded before it is sent to ssh so you need to use "" for it.

Update

Another proper way to do this actually is to use printf %q to properly quote the argument. This would make the argument safe to parse even if it has spaces, single quotes, double quotes, or any other character that may have a special meaning to the shell:

function mycommand {
    printf -v __ %q "$1"
    ssh user@123.456.789.0 "cd testdir;./test.sh $__"
}
  • When declaring a function with function, () is not necessary.
  • Don't comment back about it just because you're a POSIXist.

Starting Bash version 4.4, it can also be simplified to this:

function mycommand {
    ssh user@123.456.789.0 "cd testdir;./test.sh ${1@Q}"
}

See ${parameter@operator} section in Shell Parameter Expansion.

Solution 2 - Linux

I'm using the following to execute commands on the remote from my local computer:

ssh -i ~/.ssh/$GIT_PRIVKEY user@$IP "bash -s" < localpath/script.sh $arg1 $arg2

Solution 3 - Linux

This is an example that works on the AWS Cloud. The scenario is that some machine that booted from autoscaling needs to perform some action on another server, passing the newly spawned instance DNS via SSH

# Get the public DNS of the current machine (AWS specific)
MY_DNS=`curl -s http://169.254.169.254/latest/meta-data/public-hostname`


ssh \
    -o StrictHostKeyChecking=no \
    -i ~/.ssh/id_rsa \
    [email protected] \
<< EOF
cd ~/
echo "Hey I was just SSHed by ${MY_DNS}"
run_other_commands
# Newline is important before final EOF!

EOF

Solution 4 - Linux

Reviving an old thread, but this pretty clean approach was not listed.

function mycommand() {
    ssh [email protected] <<+
    cd testdir;./test.sh "$1"
+
}

Solution 5 - Linux

A little trick for me, using the "bash -s" they said they allow POSITIONAL ARGS but apparently the $0 is already reserved for whatever reason... Then using twice the same args rocks like so:

ssh user@host "bash -s" < ./start_app.sh -e test -e test -f docker-compose.services.yml 

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionAlexView Question on Stackoverflow
Solution 1 - LinuxkonsoleboxView Answer on Stackoverflow
Solution 2 - LinuxmuratgozelView Answer on Stackoverflow
Solution 3 - LinuxCyril Duchon-DorisView Answer on Stackoverflow
Solution 4 - LinuxTed BighamView Answer on Stackoverflow
Solution 5 - LinuxMathieu BarbotView Answer on Stackoverflow