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


116

我编写了一个在本地执行时可以正常运行的脚本:

./sysMole -time Aug 18 18

参数“ -time”“ Aug”“ 18”“ 18”已成功传递到脚本。

现在,该脚本旨在在远程计算机上执行,但是可以从本地计算机上的本地目录执行。例:

ssh root@remoteServer "bash -s" < /var/www/html/ops1/sysMole

那也很好。但是,当我尝试包括上述论点(时间为8月18日18)时,就会出现问题,例如:

ssh root@remoteServer "bash -s" < /var/www/html/ops1/sysMole -time Aug 18 18

运行该脚本后,出现以下错误:

bash: cannot set terminal process group (-1): Invalid argument
bash: no job control in this shell

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


1
“ Bash -s”是您可以从标准输入(即文件)执行脚本的方式之一。
AllenD

Answers:


160

您的示例非常接近。当将其与诸如此类的参数一起使用时,它可以正常工作。

示例脚本:

$ more ex.bash 
#!/bin/bash

echo $1 $2

有效的示例:

$ ssh serverA "bash -s" < ./ex.bash "hi" "bye"
hi bye

但是对于以下类型的参数它失败了:

$ ssh serverA "bash -s" < ./ex.bash "--time" "bye"
bash: --: invalid option
...

这是怎么回事?

您遇到的问题是,该参数(-time--time在我的示例中)被解释为切换到bash -s。您可以bash通过终止使用自己的其余命令行参数来平和它--

像这样:

$ ssh root@remoteServer "bash -s" -- < /var/www/html/ops1/sysMole -time Aug 18 18

例子

#1:

$ ssh serverA "bash -s" -- < ./ex.bash "-time" "bye"
-time bye

#2:

$ ssh serverA "bash -s" -- < ./ex.bash "--time" "bye"
--time bye

#3:

$ ssh serverA "bash -s" -- < ./ex.bash --time "bye"
--time bye

#4:

$ ssh  < ./ex.bash serverA "bash -s -- --time bye"
--time bye

注意:只是为了弄清楚重定向出现在命令行上没有什么区别,因为ssh无论如何调用带有其参数串联的远程外壳程序,引用并没有多大区别,除非您需要在远程外壳程序上引用就像示例4:

$ ssh  < ./ex.bash serverA "bash -s -- '<--time bye>' '<end>'"
<--time bye> <end>

4
你是一个天才!我该怎么做才能达到您的水平?我有很多工作要做。非常感谢。
AllenD

14
@AllenD-继续问问题,并尝试并尽可能多地参与该网站。我总是每天尝试学习新知识。在您提出问题之前,我也不知道该怎么做。8)。感谢您的提问!
slm

5
请注意,重定向可以出现在命令的任何位置:例如bash -s -- --time bye < ./ex.bash甚至< ./ex.bash bash -s -- --time bye。这是因为外壳程序首先取出重定向指令(无论它在命令中的位置如何),然后设置重定向,然后在适当的位置执行命令行的其余部分。
lesmana

@sim我正在尝试执行完全相同的操作,但是从脚本而不是从命令行执行。任何想法如何做到这一点?由于某种原因,将您的确切答案放在反引号中根本不起作用。相反,它运行本地指定的脚本,并且输出作为命令通过ssh发送到bash
krb686,

@ krb686 -我会问它作为一个新的问题:
SLM

5

关于处理任意论点

如果您实际上仅使用单个字符串,即。-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"
}

与任何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
}

用法(适用于以上两种情况)

然后可以通过以下方式调用上面给出的功能:

# if your time should be three arguments
runRemote /var/www/html/ops1/sysMole -time Aug 18 18

...要么...

# if your time should be one string
runRemote /var/www/html/ops1/sysMole -time "Aug 18 18"

-3

说aa是包含ls的本地文件

$ssh servername "cat | bash" < a.a

将127.0.0.1更改为您的远程IP

这两个给出有关伪tty分配的消息,但是它们可以工作。

$ cat a.a | ssh 127.0.0.1

$ ssh 127.0.0.1 <a.a

要么

$ cat a.a | ssh 127.0.0.1 bash or

$ ssh 127.0.0.1 bash < a.a


2
我正在努力寻找能回答这个问题的程度。
ChrisWue

质量和格式令人怀疑。我也没有看到接受的答案中没有任何新的有用信息。
朱莉·佩勒捷

@JuliePelletier我在可接受的答案中没有给出一些“猫”示例。很高兴知道其他的做事方式。
barlop

那不是一件好事。你的猫没用。
斯科特

2
哦,我的天啊。我忽略了与猫的无用使用有关的链接,因为我认为到目前为止,至少每个人都已经听说过该短语。显然,这对我而言是一个错误的假设。
斯科特
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.