큰 디렉터리를 동기화하는 bash 스크립트가 있고 --progress 기능이 훌륭하지만 이 모든 출력을 한 줄에 표시할 수 있습니까? 즉. 파일이 전송될 때 화면을 스크롤하지 않고도 진행 상황을 볼 수 있도록 --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
. 두 번째 행은 rsync
업데이트된 상태 행이 출력될 때마다 변경됩니다.
알아채다:나는 1줄 디스플레이 대신 2줄 디스플레이를 선택했습니다(그러나 여전히 스크롤하지는 않습니다!). 왜냐하면 적어도 일반적인 사용법에서는 상태 줄과 결합하면 긴 경로/파일 이름이 나타나게 되기 때문입니다. 그러나 아래에서 볼 수 있듯이 파일/경로 이름과 상태를 한 줄로 결합하면 쉽게 수정할 수 있습니다.
종료 시 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::Run
, 및 가 필요합니다 IO::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
필요에 따라 처리할 수 있습니다.
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
oneline
한 줄로 스크롤하려는 콘텐츠를 파이프하는 일반 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
.