長いコマンドsleep 10
があるとします(たとえば)。 python(具体的にはsshライブラリparamiko
)を使用して別のサーバーで実行したいと思います。
コマンドを開始し、コマンドのPIDを出力し、コマンドが終了するのを待って、最後にコマンドの終了ステータスを返す1行のコマンドが必要です。
私がこれまでに試したこと:
bash -c "echo $BASHPID ; exec sleep 10" ; echo $?
これにより、シェルのPIDが出力され、longコマンドでexecが呼び出され、待機して終了ステータスが出力されます。問題は、$BASHPID
が外部bashシェルのPIDを出力することです(bash -c cmd
を呼び出すと、実際には完全に新しいシェルが生成されないことを示している可能性がありますか?)。
上記のコマンドを3行で呼び出すと、機能します。
bash
echo $BASHPID ; exec sleep 10
echo $?
サブシェルを使用する試みも私にはうまくいきませんでした。
echo $(echo $BASHPID ; exec sleep 10) ; echo $?
これは機能しますが、サブシェルはすべての出力をechoにパイプし、echoはそれを一度に出力します。つまり、$BASHPID
はスリープが終了するまで出力されません。 PIDはすぐに印刷する必要があります。
実行すると、たとえば次のようになります。
bash -c "echo $ BASHPID; exec sleep 10"
または
echo $(echo $ BASHPID; exec sleep 10)
現在のシェルは、2番目のbash(またはサブシェル)がそれを認識する前に、$BASHPID
変数を補間しています。解決策は、現在のシェルによるこれらの変数の拡張を防ぐことです。
bash -c 'echo $BASHPID ; exec sleep 10'
これは、すでにssh
に対して実行したシェルコマンドです(リモートユーザーのログインシェルによって解釈されます)。その上で別のシェルを起動する必要はありません。 ShellがBourneのようなまたはcshのようなものであると仮定します。
echo "$$"; exec sleep 10
十分なはずです。リモートホストにbash
をインストールする必要はありません。 ssh
は、リモートコマンドの終了ステータスも報告します。印刷する必要はありません。しかし、必要に応じて、次のことができます。
sleep 10 & echo "$!"; wait; echo "$?"
$?
は$status
であるため、cshのようなシェルには適していません。
リモートユーザーのログインシェルがBourneのようであることを保証できない場合は、次のようにすることができます。
exec sh -c 'sleep 10 & echo "$!"; wait; echo "$?"'
このコマンドは、少なくともBourne、csh、およびrcファミリのシェルと互換性がある必要があります。