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

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

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

是否有一种方法来运行这个使用plink/ssh?


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

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


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

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

然后,运行脚本

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

如果您已经为脚本授予了可执行权限,那么这将起作用。


假设您的意思是希望从“本地”机器自动执行此操作,而不需要手动登录到“远程”机器,那么您应该查看名为Expect的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. unix。


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

plink root@MachineB -m local_script.sh

如果Machine A是一个基于unix的系统,你可以使用:

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

您不应该必须将脚本复制到远程服务器才能运行它。


这是一个老问题,Jason的回答很好,但我想补充一点:

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

这也可以用于su和需要用户输入的命令。(注意此处的“转义”)

由于这个答案不断获得流量,我将为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.example.com <<'ENDFTP'
test
test
ls
ENDFTP
END2
ENDSSH

实际上,您可以使用telnet、ftp等服务进行对话。但是记住,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.example.com <<-'ENDFTP'
            test
            test
            ls
        ENDFTP
    END2
ENDSSH

(我认为这应该可行)

也看到 http://tldp.org/LDP/abs/html/here-docs.html


我已经开始使用Fabric进行更复杂的操作。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 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命令。瞧。


答案在这里(https://stackoverflow.com/a/2732991/4752883),如果 您正在尝试使用plink或ssh在远程Linux机器上运行脚本。 如果脚本在linux上有多行,它就可以工作。

**但是,如果您试图运行位于本地的批处理脚本 linux/windows机器,而远程机器是windows,它由 使用**的多行

点击root@MachineB -m local_script.bat

不会工作。

只执行脚本的第一行。这可能是 丁克的限制。

解决方案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

这个bash脚本可以ssh到目标远程机器,并在远程机器上运行一些命令,在运行它之前不要忘记安装expect(在mac brew上安装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"

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

下面的命令将解决这个问题 SSH user@host " ' temp = ' ls - a ' echo $临时 “‘


我用它在远程机器上运行一个shell脚本(在/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,用于公钥认证


如果它是一个脚本,那么上面的解决方案是没问题的。

我会安排Ansible来做这项工作。它以同样的方式工作(Ansible使用ssh在Unix或Windows的远程机器上执行脚本)。

它将更具结构化和可维护性。


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

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

如果它这样做,应该工作:

myscript.sh:

#!/bin/bash

myalias $myvar
myfunction $myvar

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

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

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

设置变量、函数和别名:

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

使用env_parallel从GNU Parallel中导出myfun, myfunction, myvar和myalias到服务器:

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 definitions
work                              # call the function
EOT

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

例子:

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

看,别忘了加上bash -s


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