我必须在远程计算机上运行本地shell脚本(windows / Linux)。
我在计算机A和B上都配置了SSH。我的脚本在计算机A上,它将在远程计算机上运行一些代码
本地计算机和远程计算机可以是Windows或Unix系统。
是否可以使用plink / ssh来运行此操作?

评论

同样的问题已经在serverfault上:serverfault.com/questions/215756/…因此,迁移这个问题可能没有任何意义。

关于服务器故障的问题虽然没有那么多答案。也许这个问题应该取代那个问题。

我个人喜欢这个答案:unix.stackexchange.com/questions/87405/…

此外,由于ssh是软件开发的主要工具,因此显然应该成为主题。

Coffee和ssh问题对SO的异同程度不同。投票要求重新开放。

#1 楼

如果计算机A是Windows机器,则可以将Plink(PuTTY的一部分)与-m参数一起使用,它将在远程服务器上执行本地脚本。

plink root@MachineB -m local_script.sh


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

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


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

评论


使用-s选项有什么好处吗?该手册页使我相信,无论是否使用-s,它都会在处理完选项后处理标准输入。

–aeroNotAuto
2011年11月18日,下午5:41

对于需要sudo的脚本,请运行ssh root @ MachineB'echo“ rootpass” | sudo -Sv && bash -s'
–bradley.ayers
2012-09-20 23:32

@ bradley.ayers记得用一个'space'来启动命令以跳过历史记录(P.S.您需要HISTCONTROL = ignoreboth或ignorespace才能使它起作用)

– derenio
2013年6月23日14:38在

@ bradley.ayers在什么情况下,如果您已经以root用户身份登录,则需要sudo?

–布莱恩·施伦克(Brian Schlenker)
2014年1月20日22:41

@Agostino,您可以添加像这样的参数:ssh root @ MachineB ARG1 =“ arg1” ARG2 =“ arg2”'bash -s'
–伊夫·范·布洛霍芬(Yves Van Broekhoven)
2014年7月7日在8:28



#2 楼

这是一个古老的问题,Jason的答案很好用,但我想添加一下:

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

评论


您可以通过添加以下行来进行临时调整:#$(sleep 5)

–奥利维尔·杜拉克(Olivier Dulac)
13年2月22日在13:45

请注意,如果在终止符(<<'ENDSSH')周围加上单引号,则不会扩展字符串,也不会评估变量。如果要扩展,也可以使用<< ENDSSH或<<“ ENDSSH”。

–麦克
2013年6月18日5:38



当您需要自动化FTP等交互式命令时,可以使用Expect。

– Programaths
14年4月14日在7:35

注意,我有一个伪终端将不会被分配,因为stdin不是终端。信息。必须使用带有-t -t参数的ssh来避免这种情况。在SO上看到这个线程

–布祖特
16-4-1在12:55



如果您尝试使用<<-'END'语法,请确保使用TAB(而不是空格)缩进heredoc结束定界符。请注意,从stackexchange复制/粘贴将为您提供空间。将其更改为选项卡,缩进功能应起作用。

–fbicknel
16年6月24日在17:06



#3 楼

另外,如果要从目标主机中提取变量,请不要忘记对变量进行转义。

这使我过去很困惑。

例如:

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


打印出/ home / user2

while

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


打印出/ home / user

另一个示例:

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


正确打印出“ hello”。

评论


但是请注意以下几点:ssh user2 @ host'bash -s'echo $ HOME / home / user2 exit

–errant.info
13年4月30日在6:55

只需添加在ssh会话中运行的for循环中,不得对循环变量进行转义。

– AlexeyDaryin
2014年4月22日在8:00



在许多情况下,修复您的上一个示例的明智方法是ssh user2 @ host2'echo hello world'| awk'{print $ 1}',即在本地运行Awk脚本。如果远程命令产生了大量的输出,那么您当然要避免将其全部复制回本地服务器。顺便说一句,远程命令周围的单引号避免了任何转义的需要。

–tripleee
2015年12月29日在11:34



#4 楼

这是对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的答案结合起来得到:




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

评论


请注意,如果要传递-a这样的参数,则可以使用-。例如'ssh user @ host--a foo bar'bash -s'
–gaoithe
16 Mar 10 '16 at 17:28

如果任何env var值包含空格,请使用:ssh user @ host“ ARG1 = \” $ ARG1 \“ ARG2 = \” $ ARG2 \“”'bash -s'<<<'ENDSSH'...

–TalkLittle
16 Sep 24'4:01在

就像我在另一条评论中所写的那样,使用-s的重点是能够将参数应用于通过stdin生成的脚本。我的意思是,如果您不打算使用它,也可以忽略它。如果确实使用它,则没有理由使用环境变量:ssh user @ host'bash -s value1 value2'<<<'echo“ $ @”'

– JoL
18-09-17在21:09



#5 楼

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


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

评论


投票给你。这是一个有效的解决方案。显然,密钥必须受到保护,但是它们也可以像通过服务器端的密码一样失效。

–willasaywhat
08年11月21日在17:44

我认为这不能回答问题。该示例显示了如何运行远程命令,而不显示如何在远程计算机上执行本地脚本。

–Jason R. Coombs
10年4月28日在21:03

不确定,但是您不能使用此方法通过管道将hostA上的脚本运行在hostB上吗?

–nevets1219
2010-4-28在21:13



#6 楼

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

#7 楼

cat ./script.sh | ssh <user>@<host>


评论


有趣的是,“ cat script.sh”的此方法| ssh user @ host'是使我在另一台主机上运行Shell脚本的唯一方法。 'bash'
–Jared Still
8月6日0:18



#8 楼

尝试运行ssh user@remote sh ./script.unx

评论


仅当脚本位于远程服务器的默认(主)目录中时,此方法才有效。我认为问题是如何运行远程存储在本地的脚本。

– metasim
2010年7月20日在12:35

ssh username @ ip“ chmod + x script.sh”
ssh username @ ip“远程主机中sh文件的路径”

– Mani Deepak
2014年3月24日10:18



#9 楼

假设您是想从“本地”计算机上自动执行此操作,而无需手动登录“远程”计算机,则应查看一个称为Expect的TCL扩展,它是专门为这种情况而设计的。我还提供了用于通过SSH登录/交互的脚本的链接。

https://www.nist.gov/services-resources/software/expect

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

#10 楼

我使用此脚本在远程计算机上运行shell脚本(在/ bin / bash上进行了测试):

ssh deploy@host . /home/deploy/path/to/script.sh


#11 楼

ssh user@hostname ".~/.bashrc;/cd path-to-file/;.filename.sh"


强烈建议获取环境文件(.bashrc / .bashprofile / .profile)。在远程主机中运行某些命令之前,因为目标主机和源主机的环境变量可能会有所不同。

评论


这没有说明如何将本地脚本移动到远程主机。

– Kirelagin
4月16日晚上11:05

#12 楼

如果要执行这样的命令
temp=`ls -a` echo $temp
中的命令会导致错误。

下面的命令将解决此问题
ssh user@host ''' temp=`ls -a` echo $temp '''

#13 楼

如果您要尝试使用plinkssh在远程linux机器上运行脚本,那么这里的答案(https://stackoverflow.com/a/2732991/4752883)非常有用。
它将起作用如果脚本在linux上有多行。

**但是,如果您尝试运行位于本地
linux/windows计算机上的批处理脚本,而您的远程计算机是Windows,并且该脚本由
使用**

多行代码
plink root@MachineB -m local_script.bat

不工作。

只执行脚本的第一行。解决方案1:

要运行多行批处理脚本(特别是如果它相对简单,则由
组成),这可能是plink的局限性。几行):

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

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


#14 楼

此bash脚本会将ssh 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"


评论


如果您必须使用密码,这非常好...但是,为了让任何人在家看电视,任何ssh命令都应使用一对公钥和私钥,而不要使用密码...一旦安装到位,请更新ssh服务器以完全关闭密码

–斯科特·斯滕斯兰德
19 Mar 1 '19 at 16:25

#15 楼

chmod +x script.sh    
ssh -i key-file root@111.222.3.444 < ./script.sh


#16 楼

您可以使用runoverssh:

 sudo apt install runoverssh
 


 runoverssh -s localscript.sh user host1 host2 host3...
 


-s远程运行本地脚本


有用的标志:-g为所有主机使用全局密码(单个密码提示)-n使用SSH而不是sshpass,可用于公共密钥身份验证

#17 楼

如果是一个脚本,那么使用上述解决方案就可以了。
我将设置Ansible来完成这项工作。它的工作方式相同(Ansible使用ssh在Unix或Windows上的远程计算机上执行脚本)。
它将更加结构化和可维护。

#18 楼

首先,使用scp
将脚本复制到计算机B


[user @ machineA] $ scp / path / to / script user @ machineB:/ home / user / path


然后,只需运行脚本


[user @ machineA] $ ssh user @ machineB“ / home / user / path / script”


如果您已授予脚本可执行权限,则此方法将起作用。

评论


嗨,我应用了建议的建议,但它给了我以下错误[oracle @ node1〜] $ ssh oracle @ node2:./ home / oracle / au / fs / conn.sh ssh:node2:./ home / oracle / au / fs / conn.sh:名称或服务未知[oracle @ node1〜] $

–凯夫
08-11-20在12:47

'ssh oracle @ node2:./ home / oracle / au / fs / conn.sh'?错误的命令行,命令名称应与用户名@主机部分用空格而不是冒号分隔。

– Bortzmeyer
08年12月15日在13:37

我对此表示反对,因为它的主要主张是如果不将其复制就无法运行。

–Jason R. Coombs
10年4月28日在21:02

Jason补充说,为什么这是不正确的,而不是简单地陈述事实,这将是有帮助的。没用

–克里斯
2013年12月28日下午3:31

[user @ machineA] $ ssh root @ MachineB'bash -s'
– Oleksii Kyslytsyn
19年6月30日在16:01