当我偶然发现一个我希望阻止公司访问的恶意网站时,我在绑定服务器上编辑我的named.conf文件,然后更新我的代理服务器黑名单文件。我想用bash脚本自动化这个。假设我的脚本名为“evil-site-block.sh”并包含以下内容:
ssh root@192.168.0.1 'echo "#date added $(date +%m/%d/%Y)" >> /var/named/chroot/etc/named.conf; echo "zone \"$1\" { type master; file \"/etc/zone/dummy-block\"; };" >> /var/named/chroot/etc/named.conf'
然后以
运行$ evil-site-block.sh google.com
当我在远程机器上查看named.conf的内容时,我看到:
#date added 09/16/2014
zone "" { type master; file "/etc/zone/dummy-block"; };
我无法弄清楚如何将“google.com”作为$ 1传递。
答案 0 :(得分:1)
首先,你不希望这是两个单独重定向的echo
语句 - 这样做既低效又意味着这些行最终可能不会彼此相邻如果其他东西同时附加。
其次,更重要的是,您不希望运行的远程命令能够逃脱其引用并在您的服务器上运行任意命令(想想$1
是否'$(rm -rf /)'.spammer.com
)。
相反,请考虑:
#!/bin/bash
# ^ above is mandatory, since we use features not found in #!/bin/sh
printf -v new_contents \
'# date added %s\nzone "%s" { type master; file "/etc/zone/dummy-block"; };\n' \
"$(date +%m/%d/%Y)" \
"$1"
printf -v remote_command \
'echo %q >>/var/named/chroot/etc/named.conf' \
"$new_contents"
ssh root@192.168.0.1 bash <<<"$remote_command"
printf %q
转义数据,以便另一个bash shell中的评估传递将该内容评估回自身。因此,即使内容试图逃避其周围的引号,也可以保证远程shell(只要它是bash)正确解释内容。
答案 1 :(得分:0)
您的问题:您的整个命令都放在单引号中 - 显然是因为bash表达式在服务器上而不是在本地扩展。
但这也适用于您的$1
。
简单的解决方案:通过将本地变量包装成单引号来“中断”引用。
ssh root@192.168.0.1 'echo "#date added $(date +%m/%d/%Y)" >> /var/named/chroot/etc/named.conf; echo "zone \"'$1'\" { type master; file \"/etc/zone/dummy-block\"; };" >> /var/named/chroot/etc/named.conf'
注意:\"$1\"
→\"'$1'\"
。
注意:此解决方案是上述问题中公布的单线程的简单修复。如果其他人执行此脚本的可能性最小,或者它可以处理任何类型的外部输出,请查看Charles Duffy's solution。