【问题标题】:How to assign local variable with a remote command result in bash script?如何在 bash 脚本中使用远程命令结果分配局部变量?
【发布时间】:2014-02-04 06:47:16
【问题描述】:

我正在编写一个脚本来恢复一组服务器上的主从复制。迷失在 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 命令的结果分配局部变量。

【问题讨论】:

  • 使它适用于单行:CURRENT_LOG=$(ssh s1.somain.com "mysql -u root -pXXX --execute=\"SHOW MASTER STATUS\" -AN | awk '{print \$1}'")

标签: bash shell ssh


【解决方案1】:

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

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

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

# 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

}

【讨论】:

    【解决方案2】:

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

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

    其他答案已经涵盖了#1(即:更好的转义),所以我将涵盖#2。

    #2 很棘手,但一种方法是修改ssh 命令以打印 需要在本地运行的赋值语句。然后,您可以将其包装在运行这些赋值语句的 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)"
    }
    

    (请注意,我在前面的所有命令中都添加了&gt;&amp;2,因此它们的输出进入标准错误而不是标准输出。这是因为标准输出被捕获并在本地eval'd,显然你不想。)

    【讨论】:

      【解决方案3】:
      doRemote() {
      
      ssh localhost <<ENDSSH
              ls
              cat /etc/issue
              VAR1=\$(/home/thumper/bash/test2.sh)
              echo \$VAR1 >> /home/thumper/bash/test.txt 
      ENDSSH
      }
      
      doRemote
      

      【讨论】:

      • 试图在没有临时文件的情况下完成。
      【解决方案4】:

      尝试逃避您对 cmd-substitution 的调用

      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

      【讨论】:

      • 尝试使用 1..3 反斜杠 - 错误。
      • 我知道这听起来很疯狂,(自从我做这件事以来已经有 2-3 年了),但我知道我已经让自己感到惊讶,我不得不使用多达 5 个' \' 字符。这不会解决 var 值出现在本地环境中的问题。我认为您必须在本地捕获和解析来自远程的输出。祝你好运。
      【解决方案5】:

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

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

      【讨论】:

      • 这样它可以在远程工作,而且$CURRENT_LOG 变量也成为远程变量。如何将两个远程变量复制回原始计算机?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-01-23
      • 2020-04-22
      • 1970-01-01
      相关资源
      最近更新 更多