web-dev-qa-db-ja.com

SSH出力をbashスクリプトの変数としてキャプチャする

私はbashスクリプトを作成するときにこの問題に苦労してきました。基本的に、リモートサーバー上のプログラムの時間を測定したいので、次のコマンドを使用します:/usr/bin/time -f %e sh -c "my command > /dev/null 2>&1"プログラムを実行します。ただし、コマンド(SSH)の出力を変数にまったくキャプチャできないようです。実際、結果(時間)は標準出力に出力され続けます。

完全なコードは次のとおりです。

respond=$(ssh ${fromNode} /usr/bin/time "-f" "%e" "'sh' '-c' 'virsh migrate --live ${VM} qemu+ssh://${toNode}/system --verbose > /dev/null 2>&1'")

時間は標準出力に出力されますが、respondの値は空です。

17
Andy Dang

「time」コマンドは、結果をstdoutではなくstderrに出力します。したがって、それは変数にパイプされません。

Stderrをstdoutに再ルーティングして、目的を達成する必要があります。

 result=$(ssh Host time "command" 2>&1)

そして、完全なコードは次のようになります。

 respond=$(ssh ${fromNode} /usr/bin/time "-f" "%e" "'sh' '-c' 'virsh migrate --live ${VM} qemu+ssh://${toNode}/system > /dev/null 2>&1'" 2>&1)
37
Rogach

リダイレクトの順序を(2>&1 >/dev/nullに)入れ替えてみてください。あなたの現在のコードは、stdoutとstderrの両方を/ dev/nullに送信しています(そのため、なぜanythingが出力されるのか、ちょっと気になります)。

なぜこれが必要なのですか?構文2>&1は、「stdr(記述子2)としてstdout(記述子1)を複製する」を意味します。実際には、stderrは現在のstdoutのコピーになります。最初に>/dev/nullを指定すると、stdoutは最初に/ dev/nullにリダイレクトされ、次にstderrが現在のstdout、つまり/ dev/nullを指します。

ただし、>/dev/nullを2番目に指定すると、stderrはリダイレクトされる前に、まず現在のstdout(通常の出力ストリーム)のコピーになります。そのため、コマンドのstderrはtty(またはインタープリター)にstdoutから出力されたかのように出力しますが、stdoutは無音です。これはあなたが望む行動です。

man bashから:

リダイレクトの順序は重要であることに注意してください。たとえば、次のコマンド

ls > dirlist 2>&1

標準出力と標準エラーの両方をファイルdirlistに送信し、コマンド

ls 2>&1 > dirlist

標準出力がdirlistにリダイレクトされる前に標準エラーが標準出力として複製されたため、標準出力のみをファイルdirlistに送信します。

2
nneonneo