如何使用SSH在远程机器上运行本地外壳脚本?

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

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

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

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

1454481 次浏览
<hostA_shell_prompt>$ ssh user@hostB "ls -la"

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

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

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

然后,运行脚本

[user@machineA]$sshuser@machineB"/home/user/path/cript"

如果您已授予脚本的可执行权限,这将起作用。

假设你的意思是你想从“本地”机器自动执行此操作,而无需手动登录到“远程”机器,你应该查看一个名为EXCET的TCL扩展,它专为这种情况而设计。我还提供了一个链接,指向通过SSH登录/交互的脚本。

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

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

此外,如果您想从目标主机获取变量,请不要忘记转义变量。

这在过去抓住了我。

例如:

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

正确输出“Hello”。

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

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

plink root@MachineB -m local_script.sh

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

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

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

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

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

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

由于这个答案不断获得流量,我想为这一美妙的使用增加更多信息:

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

ssh user@host <<'ENDSSH'#commands to run on remote hostssh user@host2 <<'END2'# Another bunch of commands on another hostwall <<'ENDWALL'Error: Out of cheeseENDWALLftp ftp.example.com <<'ENDFTP'testtestlsENDFTPEND2ENDSSH

您实际上可以与telnet,ftp等一些服务进行对话,但请记住,heldoc只是将标准输入作为文本发送,它不会等待行之间的响应

我刚刚发现,如果你使用<<-END,你可以用标签缩进内部!

ssh user@host <<-'ENDSSH'#commands to run on remote hostssh user@host2 <<-'END2'# Another bunch of commands on another hostwall <<-'ENDWALL'Error: Out of cheeseENDWALLftp ftp.example.com <<-'ENDFTP'testtestlsENDFTPEND2ENDSSH

(我认为这应该工作)

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

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

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

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

我发现这非常有用,因为它将所有内容保存在一个脚本中,因此它非常可读和可维护。

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

SSHuser@hostremote_command

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

ENV_VAR_1='value e1'ENV_VAR_2='value e2'bash-c'ENV_VAR_1$ENV_VAR_2'

这使得在运行命令之前很容易定义变量。在这种情况下,回声是我们正在运行的命令。回声之前的所有内容都定义了环境变量。

所以我们结合这两个特征和YarekT的答案得到:

SSHuser@hostARG1=$ARG1 ARG2=$ARG2'bash-s'<<'ENDSSH'…

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

这里的答案(https://stackoverflow.com/a/2732991/4752883)效果很好,如果您正在尝试使用plinkssh在远程linux机器上运行脚本。如果脚本在linux上有多行,它将工作。

**但是,如果您尝试运行位于本地服务器上的批处理脚本linux/windows机器,您的远程机器是Windows,它由使用**

的多行

plink root@MachineB -m local_script.bat

不会工作。

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

解决方案1:

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

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

cd C:\Users\ipython_user\Desktoppython 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命令的脚本以及如下所指出的@Martinhttps://stackoverflow.com/a/32196999/4752883

rem Open tunnel in the backgroundstart plink.exe -ssh [username]@[hostname] -L 3307:127.0.0.1:3306 -i "[SSHkey]" -N
rem Wait a second to let Plink establish the tunneltimeout /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 tunneltaskkill /im plink.exe

这个bash脚本会ssh到目标远程机器中,并在远程机器中运行一些命令,在运行它之前不要忘记安装期望(在macbrew install expect上)

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

如果你想执行这样的命令temp='ls-a'echo$temp输入“将导致错误。

下面的命令将解决这个问题SSHuser@host"'temp='ls-a'echo$temp"'

我使用这个在远程机器上运行外壳脚本(在 /bin/bash上测试):

ssh deploy@host . /home/deploy/path/to/script.sh
cat ./script.sh | ssh <user>@<host>
ssh user@hostname ". ~/.bashrc;/cd path-to-file/;. filename.sh"

强烈建议在远程主机中运行某些内容之前,先获取环境文件(. bashrc/. bashProfile/. Profile),因为目标和源主机环境变量可能会更低。

您可以使用runoverssh

sudo apt install runoverssh
runoverssh -s localscript.sh user host1 host2 host3...

-s远程运行本地脚本


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

如果它是一个脚本,则可以使用上述解决方案。

我将设置安苏尔来执行作业。它以相同的方式工作(Anable使用ssh在远程机器上执行Unix或Windows的脚本)。

它将更加结构化和可维护。

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

不清楚本地脚本是否使用本地设置的变量、函数或别名。

如果它这样做应该工作:

myscript.sh:

#!/bin/bash
myalias $myvarmyfunction $myvar

它使用$myvarmyfunctionmyalias。让我们假设它们是在本地设置的,而不是在远程机器上设置的。

创建一个包含脚本的bash函数:

eval "myfun() { `cat myscript.sh`; }"

设置变量、函数和别名:

myvar=worksalias myalias='echo This alias'myfunction() { echo This function "$@"; }

和“导出”myfunmyfunctionmyvar,和myaliasserver使用env_parallel从GNU并行:

env_parallel -S server -N0  --nonall myfun ::: dummy

如果脚本很短,并且要嵌入到您的脚本中,并且您在bash shell下运行,并且bash shell在远程端可用,您可以使用declare将本地上下文传输到远程。定义包含将被传输到远程的状态的变量和函数。定义将在远程端执行的函数。然后在bash -s读取的here文档中,您可以使用declare -p传输变量值,并使用declare -f将函数定义传输到远程。

因为declare负责引用并将由远程bash解析,所以变量被正确引用并正确传输函数。你可以在本地编写脚本,通常我做一个长函数,并在远程完成我需要做的工作。上下文必须精心挑选,但以下方法对于任何短脚本来说都是“足够好”的,并且是安全的-应该正确处理所有角落情况。

somevar="spaces or other special characters"somevar2="!@#$%^"another_func() {mkdir -p "$1"}work() {another_func "$somevar"touch "$somevar"/"$somevar2"}ssh user@server 'bash -s' <<EOT$(declare -p somevar somevar2)    # transfer variables values$(declare -f work another_func)   # transfer function definitionswork                              # call the functionEOT

从@cglotr扩展答案。为了使用printf编写内联命令,它对简单命令很有用,并且它支持使用char转义'\n'的多行

例子:

printf "cd /to/path/your/remote/machine/log \n tail -n 100 Server.log" | ssh <user>@<host> 'bash -s'

请参阅不要忘记添加bash-s

还有另一种方法,您可以使用scp命令在主机中复制脚本,然后轻松执行。