Bash脚本无法杀死SSH远程会话启动进程的问题求助
我太懂这个坑了!你脚本里的问题核心在于:当用<< EOF这种Here Document时,里面的命令替换($(...))会被你的本地Shell先解析,而不是传到远程机器执行。
举个例子,你第一个脚本里的kill $(pidof tshark),本地Shell会先跑一遍pidof tshark,拿到你本地机器上的tshark进程PID(如果本地没跑tshark,就是空值),然后把这个PID传到远程执行kill xxx——这显然杀的不是远程的tshark进程,自然没用!
第二个脚本里的pid=$(ps -ef | grep tshark.sh ...)也是同样的道理,本地Shell先执行了这个过滤命令,拿到的是本地的进程PID,传到远程去kill,完全是南辕北辙。
而你手动SSH的时候,所有命令都是在远程Shell里执行的,pidof tshark拿到的是远程的PID,所以能正常杀掉。
下面给你几个靠谱的写法,按简洁度排序:
1. 用单引号包裹Here Document分界符(最省心)
把<< EOF改成<< 'EOF',这样整个Here Document里的内容会被当作纯文本,本地Shell不会解析任何变量或命令替换,原封不动传给远程执行:
# 启动tshark进程 ssh localadmin@10.101.30.61 &>/dev/null << 'EOF' tshark -i ens160 -w /home/localadmin/dns_traffic_61.pcap &>/dev/null & EOF # 杀死tshark进程 ssh localadmin@10.101.30.61 &>/dev/null << 'EOF' kill $(pidof tshark) EOF
2. 直接用SSH命令行传参(最简洁)
对于短命令,不用Here Document,直接把命令用单引号包裹传给SSH,本地Shell不会解析单引号里的内容:
# 启动进程 ssh localadmin@10.101.30.61 'tshark -i ens160 -w /home/localadmin/dns_traffic_61.pcap &>/dev/null &' # 杀死进程 ssh localadmin@10.101.30.61 'kill $(pidof tshark)'
3. 转义命令替换符号
如果不想改分界符,也可以把$(...)里的$转义成\$,让本地Shell跳过解析:
ssh localadmin@10.101.30.61 &>/dev/null << EOF kill \$(pidof tshark) EOF
4. 用pkill简化操作(更可靠)
如果不需要精准到单个PID,直接用pkill tshark可以一键杀死所有tshark进程(适合你只启动了一个的场景):
ssh localadmin@10.101.30.61 'pkill tshark'
5. 记录PID到文件(最稳妥)
如果担心误杀其他tshark进程,启动时把PID写入临时文件,杀进程时读取这个文件:
# 启动并记录PID ssh localadmin@10.101.30.61 'tshark -i ens160 -w /home/localadmin/dns_traffic_61.pcap &>/dev/null & echo $! > /tmp/tshark.pid' # 读取PID并杀死,最后删除临时文件 ssh localadmin@10.101.30.61 'kill $(cat /tmp/tshark.pid); rm /tmp/tshark.pid'
这里的$!是上一个后台进程的PID,能精准定位你启动的那个tshark。
可以先远程查看PID,确认命令能拿到正确的值:
ssh localadmin@10.101.30.61 'pidof tshark'
如果返回了有效的PID,再执行kill命令就肯定没问题了。
内容的提问来源于stack exchange,提问作者Giannis Pappas

