Bash

是否可以在一行上顯示 rsync 輸出?

  • January 2, 2016

我有一個 bash 腳本,它正在對一個大目錄進行 rsync,而且 –progress 功能很棒,但是是否可以在一行中顯示所有這些輸出?IE。當文件傳輸時,只需將 –progress 輸出吐到最後一行,這樣我就可以在不滾動螢幕的情況下觀看進度?

包裝腳本

這是一個用 Perl 編寫的包裝腳本的草稿,它將模擬 PTY(因此 rsync 的行為應該與在終端中的行為完全相同),並解析輸出,以便它可以保持執行的文件名和兩行顯示轉移狀態。它看起來像這樣:

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

第一行 (filename, src/test.c) 將根據 . 輸出的目前文件名而改變rsyncrsync每當輸出更新的狀態行時,第二行就會改變。

**注意:**我選擇了 2 行顯示(但仍然不會滾動!)而不是 1 行顯示,至少在我的典型用法中,我最終會得到長路徑/文件名,當結合狀態行。但是,正如您將在下面看到的,將文件/路徑名和狀態合併到一行中會很容易進行修改。

rsync退出時,腳本以相同的退出程式碼退出(因此您仍然可以擷取錯誤等)

基本原理

根據與 OP 的討論,內置rsync選項不足,它們的版本rsync較舊,並且它們的需求是獨特的。因此,我覺得自定義腳本是實現他們目標的唯一方法。

其他選擇是使用rsync已經存在的許多現有“備份”包裝實用程序中的任何一種,儘管我不知道有任何支持類似輸出的實用程序。

原始碼

#!/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
}

先決條件

該腳本需要兩個非標準模組:IPC::RunIO::Pty. 這兩個都可以cpan用 Perl 自帶的 安裝。包括我在內的許多人都喜歡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二進制位置

該腳本嘗試使用rsync自動確定二進製文件的位置which,這幾乎適用於所有環境。如果需要或需要,您還可以編輯該my $RSYNC='...'行以指定自定義位置**(重要:**在這種情況下,將反引號 (`) 更改為單引號 (’)。)

故障排除/擴展

錯誤輸出沒有特別處理,但可以對腳本進行一些小的修改。

雖然相當穩健,但這顯然是一項“快速”的工作,無法解釋極其複雜的rsync實用程序的所有可能輸出。您可能需要對其進行調整以適應您的需求,希望這相當簡單:所有輸出都進入$out變數,您可以根據需要對其進行處理。

轉換為 1 行顯示而不是 2 行顯示

如上所述,我選擇了 2 行非滾動顯示以更好地適應長路徑名。但是,將輸出轉換為 1 行顯示是微不足道的。只需將sub 中的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是一個相當隨意的printf寬度,您是對的。您可以使用類似這個問題的答案來獲取終端寬度,以便您可以相應地增大/縮小該尺寸。

引用自:https://unix.stackexchange.com/questions/252871