我编写了一个在本地执行时运行良好的脚本:
./sysMole -time Aug 18 18
论据“-时间”,“八月”,“18”, 和“18”已成功传递到脚本。
现在,该脚本被设计为在远程计算机上执行,但是从本地计算机上的本地目录执行。例子:
ssh root@remoteServer "bash -s" < /var/www/html/ops1/sysMole
这也很好用。但当我尝试包含上述论点时,问题就出现了(-时间2018年8月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
你的例子非常接近。当您将它与诸如此类的参数一起使用时,它工作得很好。
示例脚本:
$ 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
无论如何都会使用其参数的串联来调用远程 shell,引用并没有太大区别,除非您需要在远程 shell 上引用,例如例子#4:
$ ssh < ./ex.bash serverA "bash -s -- '<--time bye>' '<end>'"
<--time bye> <end>
答案2
关于处理任意争论
如果您真的只使用单个字符串,即。-time Aug 18 18
,那么您可以简单地对它进行硬编码,现有的答案会告诉您如何充分做到这一点。另一方面,如果您需要传递未知参数(例如要在其他系统上显示的消息,或者最终用户可以控制其名称的位置所创建的文件的名称),则需要更加小心。
与bash
或ksh
作为/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(例如dash
或ash
),它变得更有趣一点:
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
将命令用引号引起来,如下所示:
ssh myserver "date +\"Date: %Y%m%d %H:%M\";printf \"Uptime: \";uptime;printf \"uname: \";uname -a"
Date: 20200409 20:02
Uptime: 20:02:29 up 66 days, 55 min, 2 users, load average: 0.06, 0.05, 0.08
uname: Linux zltcmtn23aecc1rx7322 4.4.0-116-generic #140-Ubuntu SMP Mon Feb 12 21:23:04 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux
Connection to 105.31.182.217 closed.
答案4
假设 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