我必须在远程机器上运行本地 shell 脚本(windows/Linux)。
我在机器 A 和 B 上都配置了 SSH。我的脚本在机器 A 上,它将在远程机器机器 B 上运行我的一些代码。
本地和远程计算机可以是基于 Windows 或 Unix 的系统。
有没有办法使用 plink/ssh 来运行?
我必须在远程机器上运行本地 shell 脚本(windows/Linux)。
我在机器 A 和 B 上都配置了 SSH。我的脚本在机器 A 上,它将在远程机器机器 B 上运行我的一些代码。
本地和远程计算机可以是基于 Windows 或 Unix 的系统。
有没有办法使用 plink/ssh 来运行?
如果机器 A 是 Windows 机器,您可以使用带有 -m 参数的 Plink(PuTTY的一部分),它将在远程服务器上执行本地脚本。
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 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、ftp 等。但请记住,heredoc 只是将标准输入作为文本发送,它不会等待行之间的响应
编辑:我刚刚发现如果你使用<<-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
(我认为这应该有效)
此外,如果您想从目标主机获取变量,请不要忘记转义变量。
这在过去让我感到困惑。
例如:
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}'"
正确打印出“你好”。
这是 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 用户@主机 ARG1=$ARG1 ARG2=$ARG2 'bash -s' <<'ENDSSH'...
在这种情况下,我们将 ARG1 和 ARG2 设置为本地值。将 user@host 之后的所有内容作为 remote_command 发送。当远程机器执行命令 ARG1 和 ARG2 时,设置本地值,这要归功于本地命令行评估,它定义远程服务器上的环境变量,然后使用这些变量执行 bash -s 命令。瞧。
<hostA_shell_prompt>$ ssh user@hostB "ls -la"
这将提示您输入密码,除非您已将 hostA 用户的公钥复制到用户 .ssh 目录主目录上的 authorized_keys 文件中。这将允许无密码身份验证(如果被接受为 ssh 服务器配置上的身份验证方法)
我已经开始使用Fabric进行更复杂的操作。Fabric 需要 Python 和其他一些依赖项,但仅在客户端计算机上。服务器只需是 ssh 服务器。我发现这个工具比交给 SSH 的 shell 脚本强大得多,而且非常值得费心去设置(特别是如果你喜欢用 Python 编程的话)。Fabric 处理在多个主机(或特定角色的主机)上运行的脚本,有助于促进幂等操作(例如在配置脚本中添加一行,但如果它已经存在则不会),并允许构建更复杂的逻辑(例如 Python语言可以提供)。
cat ./script.sh | ssh <user>@<host>
尝试运行ssh user@remote sh ./script.unx
。
chmod +x script.sh
ssh -i key-file root@111.222.3.444 < ./script.sh
假设您的意思是要从“本地”机器自动执行此操作,而无需手动登录“远程”机器,您应该查看一个名为 Expect 的 TCL 扩展,它正是为这种情况而设计的。我还提供了一个脚本链接,用于通过 SSH 登录/交互。
我使用这个在远程机器上运行 shell 脚本(在 /bin/bash 上测试):
ssh deploy@host . /home/deploy/path/to/script.sh
ssh user@hostname ".~/.bashrc;/cd path-to-file/;.filename.sh"
强烈建议获取环境文件(.bashrc/.bashprofile/.profile)。在远程主机上运行某些东西之前,因为目标主机和源主机的环境变量可能有所不同。
temp=`ls -a`
echo $temp
如果你想在 `` 中执行这样
的命令会导致错误。
下面的命令将解决这个问题
ssh user@host '''
temp=`ls -a`
echo $temp
'''
这个 bash 脚本 ssh 到目标远程机器,并在远程机器上运行一些命令,不要忘记在运行它之前安装期望(在 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"
您可以使用runoverssh:
sudo apt install runoverssh
runoverssh -s localscript.sh user host1 host2 host3...
-s
远程运行本地脚本
有用的标志:
-g
对所有主机使用全局密码(单一密码提示)
-n
使用 SSH 而不是 sshpass,对公钥认证很有用
如果您尝试使用或在远程 linux 机器上运行脚本,这里的答案(https://stackoverflow.com/a/2732991/4752883 )非常有用。如果脚本上有多行,它将起作用。plink
ssh
linux
**但是,如果您尝试运行位于本地
linux/windows
计算机上的批处理脚本,而您的远程计算机是Windows
,并且它由使用 ** 的多行组成
plink root@MachineB -m local_script.bat
不会工作。
只会执行脚本的第一行。这可能是一个限制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`
如果您的批处理脚本相对复杂,最好使用封装 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
shell 下运行并且bash
shell 在远程端可用,您可以使用declare
将本地上下文传输到远程。定义包含将被传输到远程的状态的变量和函数。定义一个将在远程端执行的函数。然后在此处读取的文档中,bash -s
您可以使用它declare -p
来传输变量值并用于declare -f
将函数定义传输到远程。
因为declare
负责引用并将由 remote 解析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
不清楚本地脚本是否使用本地设置的变量、函数或别名。
如果这样做应该可以:
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 "$@"; }
和 "export" myfun
, myfunction
, myvar
, 和myalias
toserver
使用env_parallel
GNU Parallel:
env_parallel -S server -N0 --nonall myfun ::: dummy
如果它是一个脚本,则可以使用上述解决方案。
我会设置Ansible来完成这项工作。它以相同的方式工作(Ansible 使用 ssh 在远程机器上执行 Unix 或 Windows 的脚本)。
它将更加结构化和可维护。
首先,使用 scp 将脚本复制到机器 B
[user@machineA]$ scp /path/to/script user@machineB:/home/user/path
然后,只需运行脚本
[user@machineA]$ ssh user@machineB "/home/user/path/script"
如果您已授予脚本可执行权限,这将起作用。