题 如何使用SSH在远程计算机上运行shell脚本?


我必须在远程机器上运行shell脚本(windows / Linux)。

我在机器A和B上配置了SSH。我的脚本在机器A上,它将在远程机器B机器上运行我的一些代码。

本地和远程计算机可以是基于Windows或Unix的系统。

有没有办法使用plink / ssh运行?


1015
2017-11-20 11:44


起源


关闭作为主题,但非常受欢迎。这可以迁移到正确的StackExchange吗? - dfrankow
同样的问题已经出现在serverfault上: serverfault.com/questions/215756/... 所以迁移这个问题可能没有意义。 - sleske
关于服务器故障的问题没有那么多答案。也许这个问题应该取而代之。 - David Kennedy
我个人喜欢这个答案: unix.stackexchange.com/questions/87405/... - mikevoermans
此外,它显然应该是主题,因为ssh是软件开发的主要工具。 - static_rtti


答案:


如果机器A是Windows机器,你可以使用Plink(部分 油灰)使用-m参数,它将在远程服务器上执行本地脚本。

plink root@MachineB -m local_script.sh

如果机器A是基于Unix的系统,您可以使用:

ssh root@MachineB 'bash -s' < local_script.sh

您不必将脚本复制到远程服务器以运行它。


1029
2018-04-28 20:41



使用它有什么好处 -s 选项? 这个手册页 让我相信它会在完成处理选项时处理标准输入,无论是否 -s 使用与否。 - aeroNotAuto
对于需要的脚本 sudo, 跑 ssh root@MachineB 'echo "rootpass" | sudo -Sv && bash -s' < local_script.sh。 - bradley.ayers
@ bradley.ayers记得以'空格'开始命令以跳过历史记录(P.S。你需要 HISTCONTROL=ignoreboth or ignorespace 使它工作) - derenio
@ bradley.ayers如果你已经以root身份登录,在什么情况下你需要sudo? - Brian Schlenker
@Agostino,您可以添加如下参数: ssh root@MachineB ARG1="arg1" ARG2="arg2" 'bash -s' < local_script.sh  积分完全转到@chubbsondubs的回答如下。 - Yves Van Broekhoven


这是一个老问题,杰森的答案很好,但我想补充一点:

ssh user@host <<'ENDSSH'
#commands to run on remote host
ENDSSH

这也可以与su和需要用户输入的命令一起使用。 (注意 ' 逃过heredoc)

编辑:由于这个答案不断得到流量,我会添加更多的信息到这个heredoc的精彩使用:

您可以使用此语法嵌套命令,这就是嵌套似乎工作的唯一方式(以理智的方式)

ssh user@host <<'ENDSSH'
#commands to run on remote host
ssh user@host2 <<'END2'
# Another bunch of commands on another host
wall <<'ENDWALL'
Error: Out of cheese
ENDWALL
ftp ftp.secureftp-test.com <<'ENDFTP'
test
test
ls
ENDFTP
END2
ENDSSH

你实际上可以与telnet,f​​tp等服务进行对话。但是请记住,heredoc只是将stdin作为文本发送,它不会等待行之间的响应

编辑:我发现如果你使用,你可以缩进内部 <<-END !

ssh user@host <<-'ENDSSH'
    #commands to run on remote host
    ssh user@host2 <<-'END2'
        # Another bunch of commands on another host
        wall <<-'ENDWALL'
            Error: Out of cheese
        ENDWALL
        ftp ftp.secureftp-test.com <<-'ENDFTP'
            test
            test
            ls
        ENDFTP
    END2
ENDSSH

(我认为这应该有效)

另见 http://tldp.org/LDP/abs/html/here-docs.html


508
2017-10-06 13:11



您可以通过添加以下行来进行临时调整:#$(sleep 5) - Olivier Dulac
请注意,终止符周围有单引号(<<'ENDSSH'),字符串不会被扩展,变量将不会被评估。你也可以使用 <<ENDSSH 要么 <<"ENDSSH" 如果你想扩展。 - maackle
Expect 可以在需要自动执行FTP等交互式命令时使用。 - programaths
请注意,我有一个 Pseudo-terminal will not be allocated because stdin is not a terminal. 信息。一个人必须使用ssh -t -t 准备避免这种情况。看到这个 SO上的线程 - Buzut
如果您尝试使用<< - 'END'语法,请确保使用TAB而不是空格缩进您的heredoc结束分隔符。请注意,从stackexchange复制/粘贴将为您提供空间。将这些更改为选项卡,缩进功能应该有效。 - fbicknel


另外,如果要从目标主机中选择它们,请不要忘记转义变量。

这让我过去了。

例如:

user@host> ssh user2@host2 "echo \$HOME"

打印出/ home / user2

user@host> ssh user2@host2 "echo $HOME"

打印/ home / user

另一个例子:

user@host> ssh user2@host2 "echo hello world | awk '{print \$1}'"

正确打印出“你好”。


212
2017-11-20 12:25



但请注意以下事项: ssh user2@host 'bash -s' echo $HOME /home/user2 exit - errant.info
只是添加它 for 循环运行 ssh session不能转义循环变量。 - AlexeyDaryin
在许多情况下,修复上一个例子的理智方式是 ssh user2@host2 'echo hello world' | awk '{ print $1 }' 即在本地运行Awk脚本。如果远程命令产生巨大的输出,你当然希望避免将它全部复制回本地服务器。顺便提一下,远程命令周围的单引号可以避免任何转义。 - tripleee


这是YarekT将内联远程命令与从本地机器传递到远程主机的ENV变量结合起来的答案的扩展,因此您可以在远程端参数化脚本:

ssh user@host ARG1=$ARG1 ARG2=$ARG2 'bash -s' <<'ENDSSH'
  # commands to run on remote host
  echo $ARG1 $ARG2
ENDSSH

我发现这一点非常有用,因为它保存在一个脚本中,因此它非常易读且易于维护。

为什么会这样。 ssh支持以下语法:

ssh user @ host remote_command

在bash中,我们可以指定在单行上运行命令之前定义的环境变量,如下所示:

ENV_VAR_1 ='value1'ENV_VAR_2 ='value2'bash -c'echo $ ENV_VAR_1 $ ENV_VAR_2'

这样可以在运行命令之前轻松定义变量。在这种情况下,echo是我们正在运行的命令。 echo之前的所有内容都定义了环境变量

因此,我们结合这两个功能和YarekT的答案得到:

ssh user @ host ARG1 = $ ARG1 ARG2 = $ ARG2'bash -s'<<'ENDSSH'...

在这种情况下,我们将ARG1和ARG2设置为本地值。将user @ host之后的所有内容作为remote_command发送。当远程机器执行命令时,ARG1和ARG2被设置为本地值,这要归功于在远程服务器上定义环境变量的本地命令行评估,然后使用这些变量执行bash -s命令。瞧。


125
2017-09-09 15:00



如果你有超过1个参数通过怎么办? - Agostino
检查更新,了解如何执行2个或更多变量及其工作原理。 - chubbsondubs
请注意,如果你想传递像-a这样的args,你可以使用 - 。例如'ssh user @ host - -a foo bar'bash -s'<script.sh'。并且args也可以在重定向之后进行,例如'ssh user @ host'bash -s'<script.sh - -a foo bar'。 - gaoithe
如果任何env var值包含空格,请使用: ssh user@host "ARG1=\"$ARG1\" ARG2=\"$ARG2\"" 'bash -s' <<'ENDSSH'... - TalkLittle
这很棒...... - ATOzTOA


<hostA_shell_prompt>$ ssh user@hostB "ls -la"

这将提示您输入密码,除非您已将hostA用户的公钥复制到用户.ssh目录主页上的authorized_keys文件中。这将允许无密码身份验证(如果在ssh服务器的配置上被接受为auth方法)


89
2017-11-20 11:53



投票给你了这是一个有效的解决方案。显然,密钥必须受到保护,但它们也可以像服务器端的密码一样无效。 - willasaywhat
我不认为这回答了这个问题。该示例显示如何运行远程命令,但不显示如何在远程计算机上执行本地脚本。 - Jason R. Coombs
不确定但是你不能使用这种方法在hostA上管道你的脚本在hostB上运行吗? - nevets1219


我已经开始使用了  用于更复杂的操作。 Fabric需要Python和其他几个依赖项,但仅限于客户端计算机上。服务器只需要一个ssh服务器。我发现这个工具比传递给SSH的shell脚本更强大,值得设置的麻烦(特别是如果你喜欢用Python编程)。 Fabric处理在多个主机(或某些角色的主机)上运行脚本,有助于促进幂等操作(例如向配置脚本添加一行,但如果它已经存在则不行),并允许构造更复杂的逻辑(例如Python)语言可以提供)。


24
2018-01-26 16:17





假设您想要从“本地”机器自动执行此操作,而无需手动登录“远程”机器,您应该查看一个名为Expect的TCL扩展,它专为此类情况而设计。它的主页下面看起来有点蹩脚,但不要让它劝阻你;我还提供了一个用于通过SSH登录/交互的脚本的链接。

http://expect.nist.gov/

http://bash.cyberciti.biz/security/expect-ssh-login-script/


8
2017-11-20 12:10





试试跑步 ssh user@remote sh ./script.unx


8
2017-12-18 21:16



仅当脚本位于远程的默认(home)目录中时,此方法才有效。我认为问题是如何运行本地存储在遥控器上的脚本。 - metasim
ssh username @ ip“chmod + x script.sh”<br/> ssh username @ ip“远程主机中sh文件的路径” - mani deepak


答案在这里(https://stackoverflow.com/a/2732991/4752883)如果 你正试图在远程linux机器上运行脚本 plink 要么 ssh。 如果脚本有多行,它将起作用 linux

**但是,如果您尝试运行位于本地的批处理脚本 linux/windows 机器和你的远程机器是 Windows,它包括 多行使用**

plink root@MachineB -m local_script.bat

不会工作。

只会执行脚本的第一行。这可能是一个 限制 plink

解决方案1:

要运行多行批处理脚本(特别是如果它相对简单, 由几行组成):

如果您的原始批处理脚本如下所示

cd C:\Users\ipython_user\Desktop 
python filename.py

您可以使用“&&”分隔符将行组合在一起,如下所示 local_script.bat 文件: https://stackoverflow.com/a/8055390/4752883

cd C:\Users\ipython_user\Desktop && python filename.py

在此更改之后,您可以按照此处指出的那样运行脚本 @ JasonR.Coombs: https://stackoverflow.com/a/2732991/4752883 有:

`plink root@MachineB -m local_script.bat`

解决方案2:

如果批处理脚本相对复杂,则最好使用批处理 封装plink命令的脚本以及如下所述的脚本 在这里@Martin https://stackoverflow.com/a/32196999/4752883

rem Open tunnel in the background
start plink.exe -ssh [username]@[hostname] -L 3307:127.0.0.1:3306 -i "[SSH
key]" -N

rem Wait a second to let Plink establish the tunnel 
timeout /t 1

rem Run the task using the tunnel
"C:\Program Files\R\R-3.2.1\bin\x64\R.exe" CMD BATCH qidash.R

rem Kill the tunnel
taskkill /im plink.exe

0
2018-04-21 00:44





这个bash脚本执行ssh到目标远程机器,并在远程机器上运行一些命令,不要忘记在运行之前安装expect(在mac上) brew install expect )

#!/usr/bin/expect
set username "enterusenamehere"
set password "enterpasswordhere"
set hosts "enteripaddressofhosthere"
spawn ssh  $username@$hosts
expect "$username@$hosts's password:"
send -- "$password\n"
expect "$"
send -- "somecommand on target remote machine here\n"
sleep 5
expect "$"
send -- "exit\n"

0
2018-05-30 09:22