我想通过ssh
将小脚本发送到远程机器脚本是
#!/bin/bash
sleep 1
reboot
但我找不到事件 - 因为“!”
ssh 183.34.4.9 "echo -e '#!/bin/bash\nsleep 1\reboot>'/tmp/file"
-bash: !/bin/bash\nsleep: event not found
如何忽略“!” char所以脚本将由ssh成功发送?
备注我不能在“!”之前使用“\”因为我得到了
more /tmp/file
#\!/bin/bash
sleep 1
答案 0 :(得分:3)
在命令之前使用set +H
禁用! style history substitution
:
set +H
ssh 183.34.4.9 "echo -e '#!/bin/bash\nsleep 1\reboot>'/tmp/file"
# enable hostory expnsion again
set -H
答案 1 :(得分:0)
我认为你的命令行格式不合理。你可以发送:
ssh 183.34.4.9 'echo -e "#!/bin/bash\nsleep 1\nreboot">/tmp/file'
当我说"没有很好地形成"我的意思是你把">"在" echo"内而你忘了添加" n"在" reboot"之前,你放了" \ reboot",它将被解释为" CR" (回车)后跟" eboot"命令(我不认为存在)。
但是这里的诀窍是用(")反转昏迷(')而反过来。
答案 2 :(得分:0)
Bash以交互方式运行(这意味着您从标准输入向它提供命令而不是exec(2)
来自shell脚本的命令)因此您不需要包含该行{在这种情况下{1}} (更重要的是,bash应该忽略它,但不包括爆炸,因为它是活动历史记录机制的一部分)
但为什么呢?可执行文件中的前两个字符(任何能够从二级存储中#!/bin/bash
编译的文件,而不是你的情况)具有特殊含义(对于内核和shell):它们是幻数 标识内核正在加载的可执行文件的类型。这允许内核根据二进制可执行格式选择正确的可执行加载例程(例如,允许您在Linux内核中执行BSD程序,反之亦然)
这个神奇数字的特殊值由由两个字符exec(2)
和#
组成(按此顺序),强制内核读取完整的第一行该文件并加载该行中指定的可执行文件,允许您直接从命令行为不同的解释器执行shell脚本。它是故意完成的,因为!
字符通常在shell脚本中用作注释字符。只有在解释命令的shell不是交互式shell 时才会发生这种情况。当shell加载带有这些字符的脚本时,它通常会读取第一行,以检查它是否具有#
标记,并通过复制执行此操作的内核函数来加载正确的解释器。尽管是对shell的评论,但这样做是为了允许将不存储在辅助存储上的可执行文件视为#!
系统调用可以处理的唯一文件),但来自{{1} (就像你的一样)。
由于您的shell以交互方式运行,并且您确实希望在不更改shell的情况下执行其命令,因此您不需要该行,并且可以完全消除它而无需禁用爆炸字符。
很抱歉,但是有关使用exec(2)
选项执行shell的解决方案可能不可行,因为执行命令的shell是目标计算机中的登录shell ,所以你无法为其提供特定参数(参数由login(8)程序选择,通常不包括任意参数,如stdin
)。
最佳解决方案是完全消除-H
行,因为您不会在目标中-H
该程序。如果你想从输入行选择shell(如果用户有一个不同的shell安装为登录shell),最好在命令行中调用所需的shell并传递它(通过stdin,或者让它读取shell脚本作为文件)你要执行的shell命令(但同样没有#!/bin/bash
行)。
确保你执行整个事情非常重要,所以最好将所有脚本内容传递到目标目标中,并且一旦确定你已经通过整个事情来执行它作为一个整体。然后,您的exec(2)
第一行将被正确处理,因为可执行文件将通过内核生成的#!
运行。
示例:
#!
更复杂的系统允许在发送之前签署shell脚本,并在执行之前验证脚本签名,因此可以防止可能的特洛伊木马攻击。但是这个解释超出了范围。
另一种方法是远程使用exec(2)
命令并将所有要执行的命令传递给它。您将获得一个无会话执行环境,更适合您要求的任务(尽管您将通过电子邮件将脚本输出发送给运行该脚本的目标用户)