我有一个连接到远程计算机以执行操作的shell脚本。其中一个操作是设置一个或多个DNS服务器。虽然很容易捕获大量静态数据并通过SSH管道到远程机器:
config_ntp()
{
ssh -T admin@server_ip <<-NTPSERVER
sysconf ntp addserver $NTPSERVER
NTPSERVER
}
创建动态大小的命令列表比我想象的要复杂。我有什么:
DNSSERVERS=(8.8.8.8 8.8.8.7)
config_dns()
{
cmd=""
for server in ${DNSSERVERS[@]}; do
cmd+="network dns add nameserver $server$'\n' "
done
cmd+="service dns restart$'\n'"
echo -e "cmd: $cmd"
ssh -T admin@server_ip $cmd
}
调用此结果:
$ sh setup.sh
cmd: network dns add nameserver 8.8.8.8$'
' network dns add nameserver 8.8.8.7$'
' service dns restart$'
'
Syntax Error: Invalid character detected: '\'.
Command Result : 22 (Invalid argument)
Exiting...
那是我最新的化身。我按照其他地方的建议玩$'\n'
...之前,我刚刚\n
,导致同样的错误。
如何创建一个包含列表(可变长度,动态生成)的命令的变量,以通过ssh管道到远程机器?
答案 0 :(得分:3)
为什么你想要或需要这里的文件?如果基本上不是一个静态模板,只有一些占位符填充变量,那么通过其他方法为流程提供标准输入几乎肯定更容易。
ssh <<____HERE
commands
more commands "$variable"
____HERE
完全等同于
printf "commands\nmore commands \"%s\"\n" "$variable" | ssh
如果某些部分比仅仅打印某些部分更复杂,那么你可以使它变得非常复杂:
{ complex_function --with --options and arguments -o stdout
printf "echo 'anything we send to stdout goes into the pipe'\n"
if command; then
while another command; do
for arguments in $(something to drive a loop); do
complex stuff
done
done
fi
: and etc
} | ssh
在管道中使用大括号( commands )
而不是大括号{ commands }
在子shell中运行commands
。
您的具体问题是您无法将$'\n'
置于常规的双引号字符串中。 echo
已经产生了一个换行符,所以你似乎采取了一种非常迂回的方式来构建东西。但试试这个:
# Does this really need to be in a separate variable?
DNSSERVERS=(8.8.8.8 8.8.8.7)
config_dns()
{
{
# To be completely correct, notice quoting around array
for server in "${DNSSERVERS[@]}"; do
echo "network dns add nameserver $server"
done
echo "service dns restart"
} |
# maybe add a tee /dev/stderr or something here to see what's going on
ssh -T admin@server_ip
}
对于美学,我可能会重构
config_dns()
{
{
printf 'network dns add nameserver %s\n' "${DNSSERVERS[@]}"
printf 'service dns restart\n'
} |
ssh -T admin@server_ip
}
答案 1 :(得分:1)
首先,您将传递文本传递给命令的stdin
并将其作为参数传递。
您应该将ssh调用更改为:
ssh -T admin@server_ip <<< "$cmd"
它使用herestrings将文本传递给命令的stdin
(类似于heredocs所做的那样)。
其次,要使$'\n'
符号起作用,您需要将其置于双引号之外:
cmd+="network dns add nameserver $server"$'\n'" "
答案 2 :(得分:0)
通过ssh引用非常复杂。如果你不必这样做,就不要这样做。
不要尝试将命令与\n
分开,只需使用;
即可。它同样有效,并且不需要这么多的引用。
DNSSERVERS=(8.8.8.8 8.8.8.7)
config_dns()
{
cmd=""
for server in ${DNSSERVERS[@]}; do
cmd+="network dns add nameserver $server;"
done
cmd+="service dns restart"
echo -e "cmd: $cmd"
ssh -T admin@server_ip "$cmd"
}