rsync出力を1行に表示できますか?

rsync出力を1行に表示できますか?

大きなディレクトリを同期するbashスクリプトがあり、--progress機能は優れていますが、これらすべての出力を1行に表示できますか?つまり。ファイルが転送されたときに画面をスクロールせずに進行状況を確認できるように、 --progress 出力を最後の行と同じ行に置きます。

答え1

ラッパースクリプト

以下はPTYをエミュレートし(rsyncが端末と同じように機能する必要があります)、Perlで書かれたラッパースクリプトドラフトです。 。次のようになります。

src/test.c
    142 100%    0.19kB/s     0:00:00 (xfr#28, to-chk=0/30)

最初の行(ファイル名、src/test.c)は、出力の現在のファイル名によって変わりますrsync。 2番目の行は、rsync更新されたステータス行が出力されるたびに変更されます。

気づく:私は1行ディスプレイの代わりに2行ディスプレイを選択しました(しかしそれでもスクロールしません!)。少なくとも一般的な使用法では、ステータス行と組み合わせると長いパス/ファイル名が表示されるためです。ただし、以下に示すように、ファイル/パス名とステータスを1行にまとめると簡単に変更できます。

終了すると、rsyncスクリプトは同じ終了コードで終了します(それでもエラーなどをキャッチできます)。

基本的な

OPとの議論によると、rsync組み込みオプションが不足しrsyncており、バージョンが古く、要件が一意です。だから私はカスタムスクリプトが目標を達成する唯一の方法だと思います。

他のオプションは、同様の出力をサポートするユーティリティがわからない場合でも、多くの「バックアップ」ラッパーユーティリティのrsync1つを使用することです。

ソースコード

 #!/usr/bin/env perl

 # Custom progress wrapper for rsync

 use 5.012;
 use strict;
 use warnings;
 use autodie;
 use IPC::Run qw/run start pump finish harness/;

 my $RSYNC=`which rsync`; # Try to get rsync location from PATH
 chomp $RSYNC;

 my ($in,$out); # Input and output buffers
 my $h = harness [ $RSYNC, @ARGV ], '<pty<', \$in, '>pty>', \$out;

 local $| = 1; # Autoflush output
 print "\n\n\e[2A\e[s"; # Make room and save cursor position
 my ($file, $status) = ('',''); # Will hold filename and status lines

 while ($h->pump) { parse() }
 parse(); # Don't miss leftover output

 $h->finish;
 exit $h->result; # Pass through the exit code from rsync

 # Parse and display file/status lines from rsync output
 sub parse {
     for (split /[\n\r]+/, $out) {
         $file = $_ if /^\S/;
         $status = $_ if /^\s/;
         print "\e[u\e[0J$file\n$status\n";
     }
     $out = ''; # Clear output for next pump
 }

前提条件

このスクリプトには2つの非標準モジュールIPC::Run、およびが必要ですIO::Pty。どちらもcpanPerlに付属のプログラムを介してインストールできます。私を含む多くの人は、cpanm次の行を使用してインストールすることを好みます。

curl -L https://cpanmin.us | perl - App::cpanminus

次に、次を実行します。

cpanm IPC::Run IO::Pty

サポートされる端末タイプ

これは実際に動作しますどのシンプルなANSIカーソル移動とコードクリアを使用して画面下部の数行を継続的に覆うため、最新の端末です。

使用法

私も同じだrsync。直接指定する必要が--progress ありますが、次の行を変更していくつかのデフォルトパラメータを簡単に編集できます$h = harness ...

 my $h = harness [ $RSYNC, '--progress', @ARGV ], '<pty<', \$in, '>pty>', \$out;

rsyncバイナリ位置

rsyncwhichスクリプトは、ほぼすべての環境で動作するバイナリの場所を自動的に決定しようとします。my $RSYNC='...'必要に応じてこの行を編集してカスタムの場所を指定することもできます。(重要:この場合は、バックティック(`)を一重引用符(')に変更してください。 )

トラブルシューティング/拡張

エラー出力は特に処理されませんが、スクリプトを少し修正して処理できます。

かなり強力ですが、これは明らかに「高速」ですが、この非常に複雑なrsyncユーティリティのすべての可能な出力を説明することはできません。必要に応じて少し調整する必要があります。とても簡単だと思います。すべての出力は変数に入り、$out必要に応じて処理できます。

2ラインディスプレイから1ラインディスプレイに切り替える

上でも言ったように、私は2行を選びました。非スクロール長いパス名をよりよく収容するために表示されます。しかし、出力を単線ディスプレイに変換するのは簡単です。print ...サブ行をparse()次のように変更するだけです。

    printf "\e[u\e[0J%-30.30s %s\n", $file, $status;

または、ANSIモーションコードを完全に取り除くには、次の手順を実行します。

    printf "\r%-30.30s %-40.40s", $file, $status;
    STDOUT->flush; # $| = 1 won't help you here

これにより、次の内容が表示されます。

src/test.c               142 100%    0.19kB/s     0:00:00 (xfr#28, to-chk=0/30)

%-30.30sこれがややランダムであることがわかります。印刷機能幅、あなたは正しいです。答えのようなものを採用することができます。この問題それに応じて、サイズを増減できるように端末の幅を取得します。

答え2

oneline1行にスクロールしたいコンテンツをパイプする一般的なbashスクリプトがあります。

#!/bin/bash
cr=`tput cr;tput el`
if [ -z "$COLUMNS" ]
then COLUMNS=80
fi
while read line
do    echo -n "$cr${line:0:$COLUMNS}"
done
echo

これはtputキャリッジリターンを得ることです。行末まで消去したがって、短い行は長い行があった画面のジャンクを残しません。コマンドがstderrに出力される場合は、パイプする前にそれをstdoutにリダイレクトする必要があります。たとえばmycommand 2>&1 | oneline

関連情報