Jimbo
Jimbo

Reputation: 26624

docker-machine ssh trying to run part of command on local machine

When running the following command:

docker-machine ssh name-here "docker swarm init --advertise-addr $(hostname -I | awk '{print $1}')"

I get the following error:

hostname: illegal option -- I usage: hostname [-fs] [name-of-host]

This is because the command is attempting to run hostname -I on my local machine, running on MacOS, which doesn't have a -I flag.

Attempting to run without double quotes gives the same error.

I encapsulated the full command in double quotes so my expectation would be that the full contents of the double quotes is executed as a single argument to docker-machine ssh, but it seems that this is not the case.

I've tried single quotes (') but this interferes with awk's single quote requirement around the print. I even tried the crazy $$ as you would use in makefiles next to the hostname but this doesn't work either.

Why is $(hostname -I | awk '{print $1}') being executed on the host machine when the command is encapsulated in double quotes, and how can I run the above command correctly to initialise a docker swarm with the hostname within the machine?

Upvotes: 1

Views: 462

Answers (2)

Jimbo
Jimbo

Reputation: 26624

According to man bash:

Enclosing characters in double quotes preserves the literal value of all characters within the quotes, with the exception of $, , \, and, when history expansion is enabled, !. The characters $ and retain their special meaning within double quotes. The backslash retains its special meaning only when followed by one of the following characters: $, `, ", \, or . A double quote may be quoted within double quotes by preceding it with a backslash. If enabled, history expansion will be performed unless an ! appearing in double quotes is escaped using a backslash. The backslash preceding the ! is not removed.

So with this in mind, the following works:

docker-machine ssh name-here 'docker swarm init --advertise-addr $(hostname -I | awk '\'{print \$1}\'')'

Note how the $1 in print is escaped with a \, and one set of single quotes are also escaped around print.

Upvotes: 2

l0b0
l0b0

Reputation: 58988

Command substitutions within double quotes are always executed "immediately", that is, as part of Bash expanding the command. What you need to do to quote a command substitution is use single quotes. Compare double quotes (local substitution):

$ bash --noprofile --norc -o xtrace
bash-4.4$ ssh 127.0.0.1 "echo ${SSH_CONNECTION-No SSH connection}"
+ ssh 127.0.0.1 'echo No SSH connection'
No SSH connection

And single quotes (remote substitution):

bash-4.4$ ssh 127.0.0.1 'echo ${SSH_CONNECTION-No SSH connection}'
+ ssh 127.0.0.1 'echo ${SSH_CONNECTION-No SSH connection}'
127.0.0.1 59618 127.0.0.1 22

Upvotes: 1

Related Questions