【问题标题】:How to execute a command on a machineA from machineX through a shell script?如何通过 shell 脚本在机器上执行命令?
【发布时间】:2014-10-23 14:51:45
【问题描述】:

我有一个在 Ubuntu 12.04 上运行的应用程序服务器,我通过以下命令启动和停止它 -

用于停止应用服务器

david@machineA:/opt/kml$ /opt/kml/bin/kml_start_stop.sh stop

用于启动应用服务器

david@machineA:/opt/kml$ /opt/kml/bin/kml_start_stop.sh start

现在我正在尝试编写一个 shell 脚本,该脚本将使用上述命令停止和启动我的应用程序服务器,但我将从 machineX 运行这个 shell 脚本。从machineX,我们无需为用户david 输入任何密码即可登录machineA

例如 - 从machineX 我可以在不输入密码的情况下执行ssh david@machineA

下面是我开始的内容。一切看起来都正确吗?

#!/bin/bash

ssh david@machineA

/opt/kml/bin/kml_start_stop.sh stop
sleep 10s
/opt/kml/bin/kml_start_stop.sh start

【问题讨论】:

    标签: linux bash unix ssh ubuntu-12.04


    【解决方案1】:

    不,您不能这样做,因为ssh 将登录并等待命令,而您希望将命令提供给同一个 ssh。脚本应该看起来更像这样:

    #!/bin/bash
    while read host rest; do
      ssh david@$host <<EOF &
      /opt/kml/bin/kml_start_stop.sh stop
      sleep 10s
      /opt/kml/bin/kml_start_stop.sh start
      EOF
    done < hostlist.txt
    wait
    

    这使用了一个称为“here document”的 Bash 功能,它将文本提供给ssh 进程的标准输入。

    编辑:我添加了一个小技巧:我在启动每个 ssh 作业时将它们置于后台,因为每个作业都需要一些时间才能完成(由于睡眠,至少需要 10 秒)。然后最后我做wait 等待所有这些都完成。这样,无论有多少服务器,整个脚本都可以在 10 秒加上开销时间之外运行。

    【讨论】:

    • 非常感谢约翰。甚至巴西莱也提供了同样的东西。我很高兴我今天又学到了一件事。另一个快速的问题,假设我有多个机器名称,例如machineA,我需要在其上执行/opt/kml/bin/kml_start_stop.sh stop,然后/opt/kml/bin/kml_start_stop.sh 从将仅从machineX 运行的同一个shell 脚本开始。做这个的最好方式是什么?我正在考虑将所有应用服务器机器名称保存在一个文件中,然后读取该文件并执行命令?如果可能的话,你能提供一个例子吗?
    • @user2809564:我更新了我的答案,按照你的要求添加了一个循环。
    • 谢谢约翰,所以这个hostList.txt 文件将每一行作为机器名对吗?
    【解决方案2】:

    您可以使用here document 远程执行一些脚本:

    ssh david@machineA << EOJ
      /opt/kml/bin/kml_start_stop.sh stop
      sleep 10
      /opt/kml/bin/kml_start_stop.sh start
    EOJ
    

    在您的情况下,您还可以在本地执行多个ssh 命令和sleep

    ssh david@machineA /opt/kml/bin/kml_start_stop.sh stop
    sleep 10
    ssh david@machineA /opt/kml/bin/kml_start_stop.sh start
    

    顺便说一句,我建议学习更多关于 shell 脚本的知识。你可以阅读Advanced Bash Scripting Guide(用批判的眼光,它确实有缺陷)和documentation of GNU bash。特别是,要在多台机器上执行此操作,您可能会使用一些 bash for 循环。

    【讨论】:

    • 非常感谢巴西尔。今天学到了新东西。还有一件事,假设我有多个机器名称,例如machineA,我需要在其上执行/opt/kml/bin/kml_start_stop.sh stop,然后从仅从machineX 运行的同一shell 脚本中执行/opt/kml/bin/kml_start_stop.sh start。做这个的最好方式是什么?我正在考虑将所有应用服务器机器名称保存在一个文件中,然后读取该文件并执行命令?
    • 一般来说,我有多台运行应用服务器的机器,所以我需要从machineX运行的单个shell脚本在所有这些应用服务器上执行命令
    【解决方案3】:

    此脚本将在远程终端上执行命令。

    #!/bin/bash
    
    ssh david@machineA '/opt/kml/bin/kml_start_stop.sh stop && sleep 10s && /opt/kml/bin/kml_start_stop.sh start'
    

    如果您使用了以下脚本,则会生成一个单独的 ssh 会话 shell 以连接到远程机器,并且以下命令将在本地机器 shell 上运行,而不是在远程机器上运行

    #!/bin/bash
    
    ssh david@machineA 
    /opt/kml/bin/kml_start_stop.sh stop
    sleep 10s
    /opt/kml/bin/kml_start_stop.sh start
    

    【讨论】:

    • 这比这里的其他答案更糟糕,因为它打开了两个单独的 ssh 会话,每个会话都可能需要很长时间才能在 WAN 上设置。