从 SSH 会话中分离命令

Detach command from SSH session

我需要通过 SSH 会话在服务器上 运行 命令并关闭会话而不终止服务器上的进程。如何正确实施。

服务器和客户端是linux个系统。

请注意,我无法在服务器上安装其他软件。

看看reptyr。它是一个用于获取现有 运行 程序并将其附加到新终端的实用程序。您只需要启动一个屏幕,使用 reptyr 抓取它,然后终止 ssh 会话。 reptyr 的工作原理是使用 ptrace(2) 附加到目标程序,重定向相关文件描述符,并更改程序的控制终端。附加程序后,该程序将显示为后台运行或暂停到 shell 启动它(取决于 shell)。最好在旧的 shell 中使用 bg; disown 来删除与程序的关联,但是 reptyr 会尝试确保目标程序仍然是 运行 即使您不这样做就关闭了 shell。

如果安装了 screentmux 实用程序,您可以使用它。

在我看来,

nohup 是最好的工具。

只需像这样使用它:

nohup command &

取自nohup's man page

If standard input is a terminal, redirect it from /dev/null. If standard output is a terminal, append output to 'nohup.out' if possible, '$HOME/nohup.out' otherwise. If standard error is a terminal, redirect it to standard output. To save output to FILE, use 'nohup COMMAND > FILE'.

使用特殊工具之前

  1. 理解

    当我尝试在目标上进行后台作业时,为什么 ssh 没有 return。

    ssh user@host 'sleep 300 &'
    

    然后您必须按 Ctrl+C 来获取您的会话。

    这是因为每个连接持有3个文件描述符STDIN (0),STDOUT (1)STDERR (2)。连接将保持打开状态,而此文件描述符中至少有一个正在使用.

  2. 在运行后台任务

    之前简单地关闭它们

    这大致就是 nohup 所做的。

    ssh user@host 'exec 0<&-;exec 1>&-;exec 2>&-; sleep 300 &'
    

    这样就可以了。

  3. 正在将输出重定向到静态文件

    您可以将输出存储在位于服务器端某处的文件中:

    ssh user@host 'exec 0<&-;exec 1>>/path/to/logfile;exec 2>>/path/to/errlog; sleep 300 &'
    

    >> 用于将日志添加到现有文件...您可以通过添加 $$date +%F...

    来使用 uniq 文件
    ssh user@host 'exec 0<&-;exec 1>/path/to/logfile-$$;exec 2>&1; sleep 300 &'
    

    2>&1 引用 after 1>file 会将 STDERR 重定向为 STDOUTfile.

    ssh user@host 'exec 0<&-;exec 1>/path/to/file-$(date +%F-%T).$$;exec 2>&-;sleep 300 &'
    

    只有 STDOUT 会存储在新文件中。

使用screen

  1. 如果安装了screen

    如果您能够访问交互式前端,您可以:

    ssh user@host screen -dmS mySleep sh -c \
              "'x=0;while [ $x -lt 300 ];do echo $x;x=$((x+1));sleep 1;done'"
    

    这将启动后台作业,下一秒每 300 打印 1 ling,然后完成。

    要重新连接,您可以

    ssh -t user@host screen -x mySleep
    

    然后Ctrl+A,然后d退出后台任务

  2. 安装 screen user 级别

    如果你不能在服务器上安装一些东西,也许你可以** 在你的 $HOME 目录中安装一些东西:

    (** 如果您的体系结构与服务器上的体系结构相同,这将很容易。如果不是,您甚至可以找到兼容的二进制文件或自己交叉编译。)

     $ ssh user@host
     user@host:~$ mkdir bin lib
     user@host:~$ exit
     $ scp /path/to/bin/screen user@host:~/bin
     $ ssh user@host
     user@host:~$ bin/screen
     bin/screen: error while loading shared libraries: libutempter.so.0:
               cannot open shared object file: No such file or directory
     user@host:~$ exit
     $ scp /path/to/lib/libutempter.so.0 user@host:~/lib
     $ ssh user@host
     user@host:~$ LD_LIBRARY_PATH=~/lib bin/screen
     bin/screen: /lib/x86_64-linux-gnu/libcrypt.so.1: version `XCRYPT_2.0' 
               not found (required by bin/screen)
     user@host:~$ exit
     $ scp /lib/x86_64-linux-gnu/libcrypt.so.1  user@host:~/lib
     $ ssh user@host
     user@host:~$ LD_LIBRARY_PATH=~/lib bin/screen
     Cannot make directory '/run/screen': Permission denied
     user@host:~$ mkdir $HOME/.screen
     user@host:~$ SCREENDIR=$HOME/.screen LD_LIBRARY_PATH=~/lib bin/screen
    

    终于,现在可以了...

     $ ssh user@host SCREENDIR=\~/.screen LD_LIBRARY_PATH=\~/lib bin/screen -dmS mySleep sh -c \
              "'x=0;while [ $x -lt 300 ];do echo $x;x=$((x+1));sleep 1;done'"
     $ ssh -t user@host SCREENDIR=\~/.screen LD_LIBRARY_PATH=\~/lib bin/screen -x mySleep
    

还有很多其他选择,例如 tmuxbyobu...

最多创建您自己的包装...