ssh会话结束后运行本地命令


9

我有一些通过ssh登录的HP交换机。交换机发送一个终端命令来禁用换行(terminfo措辞中为“ rmam”),但随后无法重新启用它,这在退出ssh会话后将终端弄乱了。我可以通过运行来修复终端tput smam

在ssh会话结束后,是否有任何方法可以使ssh自动运行该命令?

将其作为外壳程序自动命令ssh运行或以别名方式在以后始终运行该命令不会杀死我,但是我更愿意通过ssh解决问题,以便我可以将命令限制为仅在连接到已知设备后才能运行-不良主机。

我的ssh客户端是OpenSSH_6.2p2,但是如果某个地方有新功能,我可以更改或更新。


我从未找到解决方法……使用telnet;)或仅使用单独的终端窗口。
ewwhite 2014年

对于一次性使用,总会有双“&”号。ssh 1.2.3.4 && tput smam
Hennes 2014年

@ewwhite:您的意思是您从未找到自动修复的方法吗?如果没有,则解决方法就在问题中。另外,虽然我知道您在开玩笑,但这并不意味着交换机会因为连接未加密而避免限制我的终端。
wfaulk 2014年

Answers:


8

OpenSSH有一个名为的选项LocalCommand,当您建立ssh连接时,该选项在客户端运行命令。不幸的是,它在建立ssh会话之前而不是之后运行命令。但这给了我一个想法,我也许可以以某种方式使前面的过程等待ssh会话结束。尽管ssh进程是LocalCommand的父PID,但事实证明,它并不是那么容易。

但是,我确实找到了在MacOS X下对我有用的东西,并且应该在(其他)BSD(如果不是Linux)上工作。我编写了一个小型C程序,该程序使用该kqueue()接口等待自己的ppid,然后在该进程退出后运行提供的命令。(下面列出了有兴趣的人的源代码。)

现在,我只需要在~/.ssh/config文件中引用此程序:

host hp-switch*
 PermitLocalCommand yes
 LocalCommand ~/bin/wait4parent 'tput smam'

这似乎很好用。那些在Linux上的人……我想您可以通过轮询LocalCommand的ppid 尝试相同的方法,并希望该pid不会被重用。(请参阅/programming/1157700/how-to-wait-for-exit-of-non-children-processes

wait4parent.c:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/event.h>
#include <sys/time.h>

int main(int argc, char **argv) {
    pid_t ppid, fpid;
    struct kevent kev;
    int kq;
    int kret;
    struct timespec timeout;

    if ( argc > 2 ) {
        fprintf(stderr, "Please quote the command you want to run\n");
        exit(-1);
    }

    ppid = getppid();

    fpid = fork();
    if ( fpid == -1 ) {
        perror("fork");
        exit(-1);
    }

    if ( fpid != 0 ) {
        exit(0);
    }

    EV_SET(&kev, ppid, EVFILT_PROC, EV_ADD, NOTE_EXIT, 0, 0);

    kq = kqueue();
    if ( kq == -1 ) {
        perror("kqueue");
        exit(-1);
    }

    kret = kevent(kq, &kev, 1, NULL, 0, NULL);
    if ( kret == -1 ) {
        perror("kevent");
        exit(-1);
    }

    timeout.tv_sec = ( 8 /*hours*/ * 60 /*minutes per hour*/ * 60 /*seconds per minute*/ );
    timeout.tv_nsec = 0;

    kret = kevent(kq, NULL, 0, &kev, 1, &timeout);
    if ( kret == -1 ) {
        perror("kevent");
        exit(-1);
    }

    if ( kret > 0 ) {
        system(argv[1]);
    }
    /* ( kret == 0 ) means timeout; don't do anything */

    exit(0);
}

2
优秀的!我在Mac上使用了此脚本,并添加了另一个系统调用,以便可以先运行本地命令(序言),然后在会话后等待第二条命令运行(结语)。
凯文·李

1
我接受了这个想法,并改进了一些代码。您可以在GitHub上
drinchev '17

4

您可以为此做一个简单的ssh包装器,并在其中指定要在ssh之后运行的命令,例如

nox:〜$ fssh foo
foo:〜$ id
uid = 0(root)gid = 0(root)组= 0(root)
foo:〜$退出
登出
到1.2.3.4的连接已关闭。
2014年10月30日星期四19:01:35欧洲中部时间
nox:〜$ cat bin / fssh 
#!/ bin / bash

eval ssh'$ @'
rc = $?
日期
退出“ $ rc”

2
是的,我说我可以做到。(为公平起见,我想我只说了“别名”,而不是“包装脚本”。)不管怎样,我不确定为什么要这么做eval。它抛弃了双引号的好处$@
wfaulk 2014年

试试看; 您仍然可以像直接使用SSH一样正常使用引号(单引号和双引号)。我使用eval是因为我曾经遇到过这样的情况:除非我对整个构造语句进行了评估,否则无法捕获构造命令的实际退出代码。
HrvojeŠpoljar2014年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.