Bash Script: How to run command with $myVar as one of the arguments? - bash

I have a bash script that SSHes into 2 machines and runs identical commands.
I'd like to store this in a var, but I'm not sure how to reference the contents of the var when running the command
ssh -o StrictHostKeyChecking=no ubuntu#123.123.123 -i ./travis/id_rsa <<-END
sudo su;
...
echo "Done!";
END
ssh -o StrictHostKeyChecking=no ubuntu#456.456.456 -i ./travis/id_rsa <<-END
sudo su;
...
echo "Done!";
END
I tried something like this but it didn't work:
script=$(cat <<-END
sudo su;
...
echo "Done!";
END
)
ssh -o StrictHostKeyChecking=no ubuntu#123.123.123 -i ./travis/id_rsa $script
ssh -o StrictHostKeyChecking=no ubuntu#456.456.456 -i ./travis/id_rsa $script

If I am at all able to understand what you are asking, you really don't want to put the commands in a variable.
for host in 123.123.123 456.456.456; do
ssh -o StrictHostKeyChecking=no ubuntu#"$host" -i ./travis/id_rsa<<-\____here
sudo -s <<-_________there
: your script goes here
________there
echo "Done."
____here
done
If you really wanted to assign a multi-line variable (but trust me, you don't) the syntax for that is simply
script='sudo -s <<\____there
: your commands
____there
echo "Done."'
But there really is no need to do this, andeit actually complicates things down the line. You see, passing in properly quoted strings as arguments to ssh is extremely tricky - you have the local shell and the remote shell and both require additional quoting or escaping in order to correctly pass through shell metacharacters; and the usual caveats with eval apply, only you are effectively running a hidden eval by way of passing in executable code as a string for the remote shell.

I believe you want to do something like this:
cmds="sudo bash -c 'command1; command2; command3;'"
ssh ... "$cmds"

Related

How to remotely execute a bash script with an option?

I am attempting to remotely execute a Bash script defined as $CONST_FILE while passing an option to it (in this case -u). Unfortunately for me, the Bash Interpreter assigns my option to ssh instead my script; causing an error as ssh does not have a -u option. The below section of code is causing a problem for me:
(ssh -o StrictHostKeyChecking=no -l $CONST_USERNAME $HOST_NAME_LOGIN<$CONST_FILE -u)
In previous Bash scripts, I have been able to execute Bash scripts via the above method so long as I was not passing an option with the script I was attempting to execute.
I have tried various placements of {} "" '' [] and other characters without success. What set of characters do I need in order for the Bash Interpreter to understand that -u needs to be consumed by $CONST_FILE instead of ssh?
The usual way is to use command like this:
ssh -o StrictHostKeyChecking=no -l $CONST_USERNAME $HOST_NAME_LOGIN "$CONST_FILE -u"
You can use also format like:
ssh -o StrictHostKeyChecking=no ${CONST_USERNAME}#${HOST_NAME_LOGIN} "$CONST_FILE -u"

Variable doesn't expand while passing as a parameter to docker-compose command inside heredoc block

I was trying to run some docker-compose command over ssh using bash script like below. I mean I have an executable shell script deploy.sh which contains below code snippets
ssh -tt -o StrictHostKeyChecking=no root#142.32.45.2 << EOF
DIR=test
echo \${DIR}
docker-compose --project-name \${DIR} up -d
EOF
But the DIR variable doesn't get expanded while passing as a parameter to docker-compose. It executes like below. While echo \${DIR} gives correct output i.e test.
docker-compose --project-name ${DIR} up -d
ssh -tt -o StrictHostKeyChecking=no root#142.32.45.2 <<'EOF'
DIR=test
echo ${DIR}
docker-compose --project-name ${DIR} up -d
EOF
Get rid of the \$ - it is preventing your variable expansion. But on second review, I see that's your intention. If you want to prevent all variable expansion until your code gets executed on the remote host, try putting the heredoc word in quotes. That way, the $ gets passed to the script being passed to ssh.
As a second suggestion ( as per my comment below ), I would consider just sending a parameterized script to the remote host and then executing it ( after changing its permissions ).
# Make script
cat >compose.sh <<'EOF'
#!/bin/bash
DIR=$1
docker-compose --project-name $DIR
EOF
scp -o StrictHostKeyChecking=no compose.sh root#142.32.45.2:
ssh -o StrictHostKeyChecking=no root#142.32.45.2 chmod +x ./compose.sh \; ./compose.sh test

running a pipe command with variable substitution on remote host

I'd to run a piped command with variable substitution on a remote host and redirect the output. Given that the login shell is csh, I have to used "bash -c". With help from users nlrc and jerdiggity, a command with no variable substitution can be formulated as:
localhost$ ssh -f -q remotehost 'bash -c "ls /var/tmp/ora_flist.sh|xargs -L1 cat >/var/tmp/1"'
but the single quote above will preclue using variable substitution, say, substituting ora_flist.sh for $filename. how can I accomplish that?
Thanks.
Something like this should work:
ssh -f -q remotehost 'bash -c "ls /var/tmp/ora_flist.sh|xargs -L1 cat >/var/tmp/1"'
So your problem was that you want the shell variable to be extended locally. Just leave it outside the single quotes, e.g.
ssh -f -q remotehost 'bash -c "ls '$filename' | xargs ..."'
Also very useful trick to avoid the quoting hell is to use heredoc, e.g.
ssh -f -q remotehost <<EOF
bash -c "ls $filename | xargs ... "
EOF

pass arguments to remote shell in ssh

for example:
ssh localhost echo *([^.])
requires me to pass -O extglob to the remote shell bash like so:
ssh localhost -O extglob echo *([^.])
however, ssh then thinks the -O is for itself, so I try again:
ssh localhost -- -O extglob echo *([^.])
but then bash thinks -- is for itself.
how can I pass -O extglob to bash through ssh?
thanks.
update: i would prefer not to ask ssh to ask bash to launch another bash:
ssh yourserver bash -O extglob -c "'echo *([^.])'"
Update: As mentioned in the comments the extglob will lead to a syntax error. I've managed it by piping the command to stdin:
ssh yourserver -- bash -O extglob <<'EOF'
echo *([^.])
EOF
I would start an additonal shell remotely. Like this:
ssh yourserver bash -O extglob -c 'ls -al'
Although it is not required in this example I would advice you to use -- after ssh arguments (as you mentioned):
ssh yourserver -- bash -O extglob -c 'ls -al'
This will prevent ssh from parsing the command to execute remotely as arguments.
But you can also pass the option to the shell ssh itself starts for you using the shopt bash builtin. Note that ; separates the two commands.
ssh yourserver -- 'shopt -s extglob; ls -al'

Run 'export' command Over SSH

When I run the following from my bash shell:
bash -c '(export abc=123 && echo $abc)'
The output is "123". But when I run it over ssh:
ssh remote-host "bash -c '(export abc=123 && echo $abc)'"
There is no output. Why is this? Is there a way around this? That is, is there a way to set an environment variable for a command I run over ssh?
Note: When I replace echo $abc with something standard like echo $USER the ssh command prints out the username on the remote machine as expected since it is already set.
I am running RHEL 5 Linux with OpenSSH 4.3
That is because when using
ssh remote-host "bash -c '(export abc=123 && echo $abc)'"
the variable gets expanded by the local shell (as it is the case with $USER) before ssh executes. Escape the $ by using \$ and it should do fine
ssh remote-host "bash -c '(export abc=123 && echo \$abc)'"
On a side note:
You don't need to export just for this.
You don't need to wrap it in ()
Like so:
ssh remote-host "bash -c 'abc=123 && echo \$abc'"
Heck, you can even leave out the bash -c ... stuff, as the ssh manpage states:
If command is specified, it is executed on the remote host instead of a login shell.
But these may be specific to your task ;)

Resources