rsync가 메시지를 한 줄씩 출력하도록 강제

rsync가 메시지를 한 줄씩 출력하도록 강제

(이 질문이 StackOverflow에 있어야 할지 여기에 있어야 할지 잘 모르겠습니다. 하지만 실제 질문은 rsync이므로 일반적으로 Linux 문제라고 생각합니다. 관리자가 동의하지 않으면 반드시 마이그레이션하십시오.)

나는 rsync다른 프로그램(이 경우 Ruby로 작성되었지만 다른 언어로도 쉽게 작성할 수 있음)에서 실행하여 출력을 한 줄씩 캡처하려고 합니다.

(Ruby에서는 다음을 통해 수행됩니다.Open3#popen3그리고IO.select수신 전화. Python에서는 사람들이 asyncio.create_subprocess_shell. )

그러나 - 내가 만난 거의 모든 다른 터미널 명령과는 달리 - rsync절대적으로거부하다이런 방식으로 실행하면(즉, 실제 tty가 있는 터미널에서 실행되지 않는 경우) 출력이 한 줄씩 기록됩니다. 대신 출력을 "버퍼링"하고 마지막에만 출력합니다(또는 아마도 버퍼가 가득 찼을 때). 아마도 flush파이프 가 아닌가 ? 이유가 무엇이든 이것은 심각한 문제입니다. 이는 내 스크립트가 사용자에게 진행률 메시지(예: 백분율)를 표시할 수 없다는 것을 의미합니다. 대신 최대 1시간 동안(또는 수술에 걸리는 시간) 완전한 무선 침묵을 볼 수 있습니다.

--outbuf=L정확히 이 상황에 대해 이 매개변수가 존재한다는 것을 읽었습니다 . 그러나 그것은작동하지 않습니다. 적어도 내 rsync 버전인 3.2.7에서는 그렇습니다.

인터넷의 누군가가 이 --msgs2stderr매개변수를 제안했지만 그것도 도움이 되지 않았습니다.

수정된 버전을 사용하여 이것이 Ruby 문제가 아닌지 확인하기 위해 Python으로 간단한 테스트를 작성했습니다.이 샘플 코드. 결과는 동일하므로 rsync에 문제가 있을 수 있습니다.

그래서 내 질문은 간단합니다. 어떻게 해야 합니까?rsync는 "저장"하고 마지막에 하나의 큰 덤프로 인쇄하는 대신 한 줄씩 진행 메시지를 출력합니까?

추가 지침

로컬에서 실행하고 있습니다 rsync. 다음은 내가 사용하는 정확한 명령의 예입니다.

rsync --verbose --msgs2stderr --progress --relative --links
--hard-links --perms --owner --group --times --sparse
--one-file-system --human-readable --delete --delete-excluded
--recursive --prune-empty-dirs --outbuf=L --from0
'/mnt/data' '/mnt/backup'
--exclude-from=/tmp/rsbackupexclusionlist20230816-2064241-6nghn7

apt-get내 Ruby 코드가 , 또는 와 같은 다른 프로그램에서 올바르게 작동하는지 확인할 수 있습니다 git. (저도 모르고 테스트 해본 적도 없습니다.)makedebootstrapyes

또한 내 연구에 따르면 rsync연결된 PTY가 감지되지 않으면 STDOUT 또는 STDERR 출력이 올바르게 플러시되지 않습니다.

그 이후로 나는 PTY를 생성하고 명령의 출력 채널을 여기에 연결하는 rsyncRuby의 제대로 문서화되지 않은 지시문을 통해 실행에 성공했습니다 . PTY.spawn그러나 그것은 이상적이지 않습니다. 한편으로는 STDOUT과 STDERR을 단일 스트림으로 결합합니다.

대다수의 다른 소프트웨어가 "그냥 작동"한다면 왜 rsync잘 작동하지 않는 걸까요? 을 사용하지 않고 작동하게 하는 방법이 있나요 PTY.spawn?

--outbuf=L아무것도 하지 않는가?

답변1

나는 이것을 복제할 수 없습니다.

저는 rsync 3.2.7을 사용하고 있으며 stderr을 잡는 Python 스크립트에서 실행하고 있습니다. 끝까지 기다리지 않고 즉시 출력을 표시합니다.

정확히 동일한 rsync 옵션을 사용하지 않았지만(예외 목록을 처리하지 않음) 관련 옵션은 모두 사용된 것 같습니다. (포함되든 안되든 상관없다고 생각합니다 --outbuf=L.

이 프로그램으로 그것을 복제할 수 있는지 확인해 보세요.

import subprocess
import sys


s = subprocess.Popen(["rsync", "-av", "--msgs2stderr", "--outbuf=L", "--progress", "lots_o_files/", "lots2/", ], stdout=subprocess.PIPE, stderr=subprocess.PIPE)


while (True):
    nextline = s.stderr.readline()
    if nextline == b'' and s.poll() is not None:
        break
    sys.stdout.write(nextline.decode())
    sys.stdout.flush()

산출:

sending incremental file list
8m28V3/qG81EA/TViGDb/
8m28V3/qG81EA/TViGDb/XOarqQ.txt
            755 100%    0.00kB/s    0:00:00 (xfr#1, ir-chk=1008/15161)
8m28V3/qG81EA/TViGDb/Zhe0F6.txt
            742 100%  724.61kB/s    0:00:00 (xfr#2, ir-chk=1007/15161)
8m28V3/qG81EA/TViGDb/a1B3ha.txt
            847 100%  827.15kB/s    0:00:00 (xfr#3, ir-chk=1006/15161)
...

출력이 즉시 인쇄되는 경우 rsync는 TTY 없이 즉시 출력을 생성해야 합니다. 이것이 끝까지 기다렸다면 우리 시스템은 약간 다를 것입니다(또는 제가 복사하지 않은 rsync 옵션이 관련이 있습니다).

관련 정보