如何在远程机器上执行本地脚本并包含参数?

All*_*enD 145 shell scripting bash options shell-script

我编写了一个在本地执行时运行良好的脚本:

./sysMole -time Aug 18 18
Run Code Online (Sandbox Code Playgroud)

参数"-time""Aug""18""18"成功传递给脚本。

现在,这个脚本被设计为在远程机器上执行,但是从本地机器上的本地目录执行。例子:

ssh root@remoteServer "bash -s" < /var/www/html/ops1/sysMole
Run Code Online (Sandbox Code Playgroud)

这也很好用。但是当我尝试包含上述参数(-time Aug 18 18) 时,问题就出现了,例如:

ssh root@remoteServer "bash -s" < /var/www/html/ops1/sysMole -time Aug 18 18
Run Code Online (Sandbox Code Playgroud)

运行该脚本后,我收到以下错误:

bash: cannot set terminal process group (-1): Invalid argument
bash: no job control in this shell
Run Code Online (Sandbox Code Playgroud)

请告诉我我做错了什么,这非常令人沮丧。

slm*_*slm 202

你很接近你的例子。当您将它与诸如此类的参数一起使用时,它工作得很好。

示例脚本:

$ more ex.bash 
#!/bin/bash

echo $1 $2
Run Code Online (Sandbox Code Playgroud)

有效的例子:

$ ssh serverA "bash -s" < ./ex.bash "hi" "bye"
hi bye
Run Code Online (Sandbox Code Playgroud)

但是对于这些类型的参数它失败了:

$ ssh serverA "bash -s" < ./ex.bash "--time" "bye"
bash: --: invalid option
...
Run Code Online (Sandbox Code Playgroud)

这是怎么回事?

您遇到的问题是参数 ,-time--time在我的示例中,被解释为切换到bash -s。您可以bash通过使用--参数终止它为自己获取任何剩余的命令行参数来安抚它。

像这样:

$ ssh root@remoteServer "bash -s" -- < /var/www/html/ops1/sysMole -time Aug 18 18
Run Code Online (Sandbox Code Playgroud)

例子

#1:

$ ssh serverA "bash -s" -- < ./ex.bash "-time" "bye"
-time bye
Run Code Online (Sandbox Code Playgroud)

#2:

$ ssh serverA "bash -s" -- < ./ex.bash "--time" "bye"
--time bye
Run Code Online (Sandbox Code Playgroud)

#3:

$ ssh serverA "bash -s" -- < ./ex.bash --time "bye"
--time bye
Run Code Online (Sandbox Code Playgroud)

#4:

$ ssh  < ./ex.bash serverA "bash -s -- --time bye"
--time bye
Run Code Online (Sandbox Code Playgroud)

注意:只是为了说明重定向出现在命令行上的任何地方都没有区别,因为ssh无论如何调用远程shell并连接其参数,引用没有太大区别,除非您需要在远程shell上引用就像例子#4:

$ ssh  < ./ex.bash serverA "bash -s -- '<--time bye>' '<end>'"
<--time bye> <end>
Run Code Online (Sandbox Code Playgroud)

  • @AllenD - 继续提问,并尽可能多地尝试参与该网站。我总是每天尝试学习新的东西。在您提出问题之前,我也不知道该怎么做。8-)。感谢您的提问! (23认同)
  • 请注意,重定向可以出现在命令中的任何位置:例如`bash -s -- --time bye &lt; ./ex.bash` 甚至`&lt; ./ex.bash bash -s -- --time bye `. 这是因为 shell 首先取出重定向指令(不管它在命令中的哪个位置),然后设置重定向,然后在重定向到位的情况下执行命令行的其余部分。 (7认同)
  • 你是天才!我该怎么做才能达到你的水平?我有很多工作要做。非常感谢。 (5认同)

Cha*_*ffy 8

关于处理任意参数

如果你真的只使用一个字符串,即。-time Aug 18 18,然后您可以简单地对其进行硬编码,现有的答案会告诉您如何充分地做到这一点。另一方面,如果您需要传递未知参数(例如要在其他系统上显示的消息,或者在最终用户可以控制其名称的位置创建的文件的名称),则需要更加小心。


bashksh作为/bin/sh

如果您的遥控器/bin/sh是由 bash 或 ksh 提供的,您可以使用不受信任的参数列表安全地执行以下操作,这样即使是恶意名称(如$(rm -rf $HOME).txt)也可以安全地作为参数传递:

runRemote() {
  local args script

  script=$1; shift

  # generate eval-safe quoted version of current argument list
  printf -v args '%q ' "$@"

  # pass that through on the command line to bash -s
  # note that $args is parsed remotely by /bin/sh, not by bash!
  ssh user@remote-addr "bash -s -- $args" < "$script"
}
Run Code Online (Sandbox Code Playgroud)

任何符合 POSIX 的 /bin/sh

为了安全地抵御足够恶意的参数数据(printf %q当被转义的字符串中存在不可打印的字符时,尝试利用bash 中使用的非 POSIX 兼容引用),即使/bin/sh是基线 POSIX(例如dashash),它变得更有趣了:

runRemote() {
  local script=$1; shift
  local args
  printf -v args '%q ' "$@"
  ssh user@remote-addr "bash -s" <<EOF

  # pass quoted arguments through for parsing by remote bash
  set -- $args

  # substitute literal script text into heredoc
  $(< "$script")

EOF
}
Run Code Online (Sandbox Code Playgroud)

用法(对于上述任何一种)

然后可以调用上面给出的函数:

# if your time should be three arguments
runRemote /var/www/html/ops1/sysMole -time Aug 18 18
Run Code Online (Sandbox Code Playgroud)

...或者...

# if your time should be one string
runRemote /var/www/html/ops1/sysMole -time "Aug 18 18"
Run Code Online (Sandbox Code Playgroud)