我的脚本旨在使用提取文本日志文件tail -f
并使用提取 wireshark 跟踪tshark
。但我不知道这些是否是实现我的目标的最佳选择。
我的脚本必须ssh
进入一台机器(我称之为服务器),然后从那台机器ssh
进入另一台机器(称为刀片),所以我创建了这两个函数来简化发送命令:
processIDs=()
# sends command $2 to server $1, piping output to file $3 on local machine
server_cmd() {
ssh -i /home/$USER/.ssh/id_rsa root@$1 $2 1>>$3 2>>$errorOutput &
processIDs+=($!)
}
# sends command $3 to blade $2 of server $1, piping output to file $4 on local machine
blade_cmd() {
server_cmd $1 "ssh root@$2 \"$3\"" $4
}
ssh
每次我向后台发送调用时,进程 ID 都会存储到数组中。
在我的脚本中,我对该函数进行了不同次数的调用(取决于用户的选择)blade_cmd
:
blade_cmd $server_ip $server_blade_ip "tail -f \\\$(ls -1tr ${path}_Debug_* | tail -1)" debug.log
blade_cmd $server_ip $server_blade_ip "tail -f \\\$(ls -1tr ${path}_Report_* | tail -1)" report.log
blade_cmd $server_ip $server_blade_ip "tshark -i eth7 -w -" tshark.pcap
然后执行生成日志/跟踪的操作,然后像这样终止进程:
# kill all generated processes on the array
for i in ${!processIDs[@]}; do
kill ${processIDs[i]}
wait ${processIDs[i]} 2>>$errorOutput
done
但是通过这种设置,远程机器上的进程就不会被终止,而是处于挂起状态。
我发现终止进程的解决方案是使用ssh
标志-tt
强制调用tty
,这确实解决了不传播来自本地机器的终止的问题,但随后我收到的日志/跟踪会被登录横幅和各种换行符破坏,这会使日志,特别是跟踪变得tshark
毫无用处。
我需要一些关于如何继续进行此事的指导。
答案1
tshark -w - …
在我的测试中,当本地退出时,远程会自动退出ssh
,即使我ssh
像你一样链接 s;至少在tshark
尝试继续写入时。我认为这是此处描述的机制:tail -f … | grep -q …
为什么找到匹配项后不退出?
注意本地ssh
退出后的第一次写入可能只会导致中间ssh
(在服务器)退出,下一次写入将导致tshark
退出。
类似于tail -f
刀刃,但这tail
可能(或可能不)“智能”并能检测到破裂的管道(请参阅链接的答案)。但中间体还ssh
没有那么智能。
所以是的,在某些情况下“远程机器上的进程[…]处于悬而未决的状态”。
有一个技巧可以让远程tshark
或tail -f
退出在本地ssh
退出后立即退出。您不能将此技巧用于应从 stdin 读取的远程命令(即最终从本地的 stdin 读取ssh
),但由于tshark
和tail -f
不使用它们的 stdin,在这种情况下这个技巧很有用。这是技巧:
在刀刃,而不是tshark …
运行:
# shell code for blade
tshark … & cat >/dev/null; kill "$!"
注意,您需要在本地调整引用,以便$!
扩展刀刃,而不是更早。为了简洁起见,我决定以 shell 的形式发布命令刀刃应得。
tshark …
现在在后台运行刀刃,但这不应该阻止它工作。cat
最终从本地的标准输入读取ssh
,它将一直停留在那里,直到本地ssh
退出或其标准输入中断或耗尽。如果本地退出ssh
或其标准输入中断或耗尽,cat
将获得 EOF 条件并退出。然后kill
将tshark
终止刀刃。
当tshark
和不再存在cat
时kill
,壳刀刃sshd
退出和相关实例刀刃退出,ssh
等等服务器也退出了。很干净。
可以使用相同的技巧来tail -f …
退出。
现在我们需要照顾当地的情况。
远程cat
将读取本地ssh
读取的内容。如果没有重定向,本地ssh
将使用本地脚本的标准输入(标准输入可能是终端、常规文件或其他任何东西)。通常,您可能不想让本地ssh
使用脚本的标准输入。此外,如果 EOF 条件过早发生,cat
则会过早退出;我们希望它仅在本地ssh
退出后退出,而不是在本地标准输入耗尽时退出。出于这些原因,最好将本地的标准输入连接ssh
到脚本的标准输入以外的其他东西。这不可能是/dev/null
因为 EOF 会立即发生。这不应该是/dev/zero
因为它会白白传输零字节。这可能是tail -f /dev/null
:
# locally inside your function
tail -f /dev/null | ssh … &
但随后$!
会告诉您 PID,ssh
并且在终止ssh
此本地进程后tail
会保留,除非它是“智能的”(再次参见链接的答案)。只有当您的本地进程tail
是“智能的”时,这才是一种干净的方法,不会留下挂起的进程。
或者,您可以使用虚拟 fifo。您应该事先将其打开以进行读写,这样就不会出现任何停滞。不过,无需通过 fifo 传递任何内容。示例:
# locally
mkfifo dummy
exec 3<>dummy
rm dummy
# then inside your function
<&3 ssh … &
您可以将同一个 fifo 用于多个 实例ssh
。在示例中,我在打开文件描述符后立即将 fifo 从目录中取消链接,因此以后无需维护。当 fifo 不再使用时,内核将真正摆脱它。
不管怎样(比如用“智能”tail
或先进先出),现在只要ssh
在本地杀死,然后远程cat
打开刀刃会看到 EOF 并退出,刀刃和服务器将如上所述发生。