何か問題があるようですopenssh
。bash
シェルからstderr
リダイレクトするとstdout
永久にブロックされるため、次のことを行う必要がありますKeyboardInterrupt
。
$ ssh -fTNF './config' -MS './sockd5/ctrl_socket' -i './keys/id_rsa' -l 'root' -p '22' 'example.com' 2>&1 | cat -A; echo OK
ControlSocket ./sockd5/ctrl_socket already exists, disabling multiplexing^M$
^C
リダイレクトせずに同じコマンドが正常に動作します。
$ ssh -fTNF './config' -MS './sockd/ctrl_socket' -i './keys/id_rsa' -l 'root' -p '22' 'example.com' | cat -A; echo OK
ControlSocket ./sockd/ctrl_socket already exists, disabling multiplexing
OK
なぜこれが起こるのですか?解決策はありますか?
答え1
ssh -f
ホストに接続して認証した後、「バックグラウンドに移動」すると、stdin、stdout、および stderr の元の開いたハンドルが維持され、そのハンドルが別のプロセス (たとえば stdout + stderr cat -A
) にパイプされている場合、必要なくなった場合でもプロセスをアクティブに保つ効果があります。
ssh
呼び出してプロセス自体をデーモン化します。daemon(3)
ライブラリ関数ですが、それを呼び出すために使用されるため、noclose = 1
stdin / stderr / stdoutをリダイレクトできません/dev/null
。
この問題は、最新バージョンで部分的に修正されましたopenssh
(メイン制御プロセス - stdinとstdoutの場合)。2010年、標準エラー2016年;セッションプロセスの場合 - 標準出力2017年)しかし、古いsshを実行する必要がある場合、またはstderrへのこだわりを停止する必要がある場合は、唯一の「解決策」はhackを使用し、を使用するラッパーで関数をオーバーライドするLD_PRELOAD
ことです。daemon(3)
noclose = 0
$ cat daemon-force-close.c
#define _GNU_SOURCE
#include <unistd.h>
#include <dlfcn.h>
#include <err.h>
int daemon(int nochdir, int noclose){
static int (*orig)(int, int);
if(!orig && !(*(void**)&orig = dlsym(RTLD_NEXT, "daemon")))
errx(1, "%s", dlerror());
return orig(nochdir, 0);
}
$ cc -shared -Wall -O2 daemon-force-close.c -ldl -o daemon-force-close.so
$ LD_PRELOAD=./daemon-force-close.so \
ssh -Nf dummy@localhost -MS ./ctlsock 2>&1 | cat -A
dummy@localhost's password:
$
[no Ctrl-C needed]
$ ssh -S ~/w/c/ctlsock dummy@localhost
Last login: Tue May 28 21:04:26 2019 from ::1
...
答え2
なぜこれが起こるのですか?
シェルが到着する前にcat
シャットダウンが必要ですecho
。存在するため、「永久にブロック」されますcat
。
解決策はありますか?
Bashはブロックなしで実行するためにプロセスオーバーライドを使用しますcat
。cat
邪魔にならない場合は、本当にまともなecho OK
場合にのみ(&&
またはを使用して)$?
簡単です。例:
ssh -f … > >(cat -A) 2>&1 && echo OK; echo "The script goes on."
これでバックグラウンドに移動するcat
前後に動作しますssh
が、スクリプトはssh
実行されるとすぐに続行されます(またはssh
バックグラウンドに移動せずに失敗します)。