如何在bash脚本中使用远程命令结果分配局部变量?

时间:2014-01-15 16:56:14

标签: bash shell ssh

我正在编写一个脚本来恢复一组服务器上的Master-Slave复制。在bash语法中丢失,试图分配一个局部变量,其结果是远程运行命令替换为本地值:

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
}

分配CURRENT_ *变量的两行是问题:mysql -u...命令在本地执行,而不是远程会话。

请建议如何远程运行,使用远程mysql命令的结果分配本地变量。

5 个答案:

答案 0 :(得分:6)

尝试转义ENDSSH,如下所示,以便在远程主机上进行变量评估:

ssh s1.domain.com <<\ENDSSH
    # ...
ENDSSH

答案 1 :(得分:2)

尝试转义您的cmd替换调用

CURRENT_LOG=`mysql -u root -pXXX --execute="SHOW MASTER STATUS" -AN | awk '{print $1}'`

现在是

CURRENT_LOG=\`mysql -u root -pXXX --execute="SHOW MASTER STATUS" -AN | awk '{print $1}'\`

或加入90年代;-)并使用$( ... )形式的cmd替换(也转义)

CURRENT_LOG=\$(mysql -u root -pXXX --execute="SHOW MASTER STATUS" -AN | awk '{print $1}' )

您可能必须使用多个'\'字符才能正确转义。

IHTH

答案 2 :(得分:2)

所以,你有两个完全不同的问题:

  • 您正在本地运行嵌入式命令,在调用ssh之前,您打算远程运行,作为通过ssh传递的输入的一部分。
  • 您要在远程主机上分配要在本地主机上分配的变量。

其他答案已经涵盖#1(即:更好的逃避),所以我将覆盖#2号。

#2很棘手,但一种方法是将ssh命令修改为 print 需要在本地运行的赋值语句。然后,您可以将其包装在运行这些赋值语句的eval命令中。

总而言之,你最终会得到这样的结论:

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)"
}

(注意我向所有以前的命令添加了>&2,因此它们的输出变为标准错误而不是标准输出。这是因为标准输出被捕获并且eval在本地输出,显然你不想要。)

答案 3 :(得分:0)

doRemote() {

ssh localhost <<ENDSSH
        ls
        cat /etc/issue
        VAR1=\$(/home/thumper/bash/test2.sh)
        echo \$VAR1 >> /home/thumper/bash/test.txt 
ENDSSH
}

doRemote

答案 4 :(得分:0)

也可以将整个here文档的内容存储在变量中,然后将此变量作为参数传递给ssh命令。

添加一些echo语句可以访问本地计算机上的${CURRENT_LOG}${CURRENT_POS}变量。只需确保下面的$ssh_output仅包含echo语句的输出(另请参阅:Run a parallel command while waiting for ssh)。

如果ssh要执行sudo提示输入密码,请不要从此处的文档重定向stdin。

# 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

}