Reputation: 1601
I'm writing a script to restore Master-Slave replication on a set of servers. Lost in bash syntax trying to assign a local variable with a result of a remotely ran command substitution with local values:
function doRemote() {
ssh s1.domain.com <<ENDSSH
mysql -u root -pXXX --execute="DROP DATABASE db; CREATE DATABASE db;"
mysql -u root -pXXX --database=db < $WORKDIR$FILENAME
sudo rm -rf /var/log/mysql/db-bin.*
mysql -u root -pXXX --execute="FLUSH LOGS;"
CURRENT_LOG=`mysql -u root -pXXX --execute="SHOW MASTER STATUS" -AN | awk '{print $1}'`
CURRENT_POS=`mysql -u root -pXXX --execute="SHOW MASTER STATUS" -AN | awk '{print $2}'`
# ...
ENDSSH
}
The two lines assigning CURRENT_* variables are the problem: the mysql -u...
command gets executed locally, instead of remote session.
Please advice how to run that remotely, assigning the local variable with a result of a remote mysql command.
Upvotes: 5
Views: 5310
Reputation: 11
It is also possible to store the contents of the entire here document in a variable and then pass this variable as an argument to the ssh
command.
Adding some echo
statements makes it possible to access the ${CURRENT_LOG}
and ${CURRENT_POS}
variables on the local machine. Just make sure $ssh_output
below only contains the output of the echo
statements (but also see: Run a parallel command while waiting for ssh).
Do not redirect stdin from a here document if ssh
is going to execute sudo
prompting for a password.
# untested
function doRemote() {
cmds="$(cat <<'ENDSSH'
mysql -u root -pXXX --execute="DROP DATABASE db; CREATE DATABASE db;"
mysql -u root -pXXX --database=db < $WORKDIR$FILENAME
sudo rm -rf /var/log/mysql/db-bin.*
mysql -u root -pXXX --execute="FLUSH LOGS;"
CURRENT_LOG=`mysql -u root -pXXX --execute="SHOW MASTER STATUS" -AN | awk '{print $1}'`
echo "export CURRENT_LOG='${CURRENT_LOG}';"
CURRENT_POS=`mysql -u root -pXXX --execute="SHOW MASTER STATUS" -AN | awk '{print $2}'`
echo "export CURRENT_POS='${CURRENT_POS}';"
# ...
ENDSSH
)"
# use ssh -t for sudo command
ssh_output="$(ssh -t s1.domain.com "$cmds")"
eval "$ssh_output"
return 0
}
Upvotes: 1
Reputation: 183251
So, you have two completely distinct problems:
ssh
, that you intended to be running remotely, as part of the input passed over ssh
.Other answers have already covered #1 (namely: better escaping), so I'll cover number #2.
#2 is tricky, but one approach is to modify the ssh
command to print the assignment statements that need to run locally. You can then wrap it in an eval
command that runs those assignment statements.
All told, you end up with something like this:
function doRemote() {
eval "$(ssh s1.domain.com <<' ENDSSH'
mysql -u root -pXXX --execute="DROP DATABASE db; CREATE DATABASE db;" >&2
mysql -u root -pXXX --database=db < $WORKDIR$FILENAME >&2
sudo rm -rf /var/log/mysql/db-bin.* >&2
mysql -u root -pXXX --execute="FLUSH LOGS;" >&2
printf 'CURRENT_LOG=%q\n' `mysql -u root -pXXX --execute="SHOW MASTER STATUS" -AN | awk '{print $1}'`
printf 'CURRENT_POS=%q\n' `mysql -u root -pXXX --execute="SHOW MASTER STATUS" -AN | awk '{print $2}'`
# ...
ENDSSH)"
}
(Note that I added >&2
to all the previous commands, so their output goes to standard-error instead of standard-output. This is because standard-output gets captured and eval
'd locally, which obviously you wouldn't want.)
Upvotes: 2
Reputation: 147
doRemote() {
ssh localhost <<ENDSSH
ls
cat /etc/issue
VAR1=\$(/home/thumper/bash/test2.sh)
echo \$VAR1 >> /home/thumper/bash/test.txt
ENDSSH
}
doRemote
Upvotes: 0
Reputation: 37258
Try escaping your calls for cmd-substitution
CURRENT_LOG=`mysql -u root -pXXX --execute="SHOW MASTER STATUS" -AN | awk '{print $1}'`
now is
CURRENT_LOG=\`mysql -u root -pXXX --execute="SHOW MASTER STATUS" -AN | awk '{print $1}'\`
or join the 90's ;-) and use the $( ... )
form of cmd substitution (escaped also)
CURRENT_LOG=\$(mysql -u root -pXXX --execute="SHOW MASTER STATUS" -AN | awk '{print $1}' )
You might have to use more than one '\'
char to get proper escaping.
IHTH
Upvotes: 2
Reputation: 274532
Try escaping ENDSSH
as shown below, so that variable evaluation occurs on the remote host:
ssh s1.domain.com <<\ENDSSH
# ...
ENDSSH
Upvotes: 6