在远程主机上使用本地输入文件运行本地脚本

在远程主机上使用本地输入文件运行本地脚本

我有一个本地脚本,想在多个远程服务器上运行。我使用的命令语法是:

ssh <remote_server> "bash -s" < ./local_script.sh

这工作得很好,甚至可以让我将参数传递给本地脚本.sh。但是,我真的很想将输入文件传递给它,如下所示:

local_script.sh < local_file.txt

结合这两个语句可以得出:

ssh <remote_server> "bash -s" < ./local_script.sh < local_file.txt

当我运行这个时,我得到

bash: line 1: FOO: command not found
bash: line 2: BAR: command not found
bash: line 3: BAZ: command not found
...

其中 FOO、BAR、BAZ 等是每行的第一个单词本地文件.txt

FOO     FOO_PARAM1
BAR     BAR_PARAM1
BAZ     BAZ_PARAM2
...

所以,看起来"bash -s"远程服务器正在解释本地文件.txt作为脚本文件,而不是输入文件本地脚本.sh。有什么方法可以解决这个问题(除了创建包装脚本之外)?

答案1

虽然ssh提供了两个独立的输出流(用于 stdout 和 stderr),但它只提供一个输入流(stdin)。因此,您需要通过不同的机制传递脚本内容和输入文件。

例如,一个通过变量,一个通过 stdin:

LC_CODE=$(cat local_script.sh) ssh host 'eval "$LC_CODE"' < input

(假设您的ssh客户端传递LC_*变量(SendEnvin ssh_config)并且sshd服务器接受它们(AcceptEnvin sshd_config))

或者简单地将 的内容local_script.sh作为远程 shell 代码传递,假设远程用户的登录 shell 是该脚本语法的正确选择:

ssh host "$(cat local_script.sh)" < input

或者将代码和输入连接到ssh的 stdin,如下所示:

{
  echo '{'; cat local_script.sh; echo '}; exit'
  cat input
} | ssh host 'bash -s some arguments'

这里使用bashbecausebash将负责一次一个字节地读取输入,以免读取超过该}; exit行,而并非所有其他shell都这样做。

或者如果sed远程主机上是 GNU sed

echo '#END-OF-SCRIPT' | cat local_script.sh - input |
  ssh host 'set some arguments; eval "$(sed -u "/^#END-OF-SCRIPT/q")"'

(此处由远程用户的登录 shell 评估代码并假设它类似于 Bourne)

答案2

这是使用 BASH 'here-strings' 运算符 ('<<<') 的更优雅的解决方案

ssh -t host "/bin/bash <(base64 --decode <<<'$(base64 < script)' )"

IT 获取脚本,将其转换为 Base64 字符串,在 SSH 命令中将其转换回来并将其作为管道文件名提供给 bash。

对于建立交互式 shell 的脚本,请在“管道文件名”前面加上“--rcfile”

ssh -t host "/bin/bash --rcfile <(base64 --decode <<<'$(base64 < script)' )"

更多关于... https://antofthy.gitlab.io/info/apps/ssh_remote_commands.txt

答案3

这很有效,甚至可以让您将多个文件的内容传递给脚本:

ssh host "bash -s -- '$(cat local_file_1.txt)'  '$(cat local_file_2.txt)'" < local_script.sh

解释是它将在登录时ssh执行bash -s,脚本参数是 后的所有内容--。因此,$1的内容将是local_file_1.txt$2的内容将是local_file_2.txtbash -s从来自 的 stdin 读取命令< local_script.sh

相关内容