在 Python 的 Fabric 中处理回车符 return (\r)

Handling of carriage return (\r) character in Python's Fabric

我正在使用 Python 的 Fabric 通过 ssh 在远程主机上执行一些任务。
当显示子任务的进度条时,其中一项任务在其输出中使用回车 return 字符。类似于此:

int main(int argc, char* argv[]) {

        int i;

        for (i = 0; i <= 5; ++i) {
                printf("\rProgress: %d%%", (int)(100 * ((float)i / 5)));
                fflush(stdout);
                sleep(1);
        }
        printf("\n");

        return 0;
}

当使用 python 的结构运行时:

def some_task():
    with settings(user = 'root'):
        run('./task_with_progress_bar.out')

tasks.execute(some_task, hosts = ['server_name'])

Fabric 将忽略 \r,而不是在一行中显示进度条,我将得到的是:

[server_name] Executing task 'some_task'
[server_name] run: ./task_with_progress_bar.out
[server_name] out:
[server_name] out: Progress: 0%
[server_name] out: Progress: 20%
[server_name] out: Progress: 40%
[server_name] out: Progress: 60%
[server_name] out: Progress: 80%
[server_name] out: Progress: 100%
[server_name] out:

似乎 \r 被视为 \n...

上面的例子还不错,但我的实际任务 运行 充满了进度条,这些进度条以较小的步骤前进,这会用不必要的输出污染整个控制台。

有没有办法以某种方式自定义输出,以便 Fabric 不会忽略 \r,但仍保持相同的通用格式:[<server_name>] <action_being_taken>?我喜欢这种格式,它整洁干净。

问题是织物正在 \n 中转换 \r

这个问题的解决方法是创建一个类似 class 的文件,并将其作为 stdout 参数传递给 run,这样我们就可以处理被调用程序产生的输出,将 \n 翻译回 \r。编写这样的 class 的挑战是确定必须将哪个 \n 转换为 \r。这是寻找 "Progress:" 来识别此类情况的尝试:

class FixProgress:
    def __init__(self):
        self.saw_progress = False

    def write(self, s):
        if 'Progress:' in s:
            self.saw_progress = True
        if s == '\n' and self.saw_progress:
            sys.stdout.write('\r')
            self.saw_progress = False
        else:
            sys.stdout.write(s)

    def flush(self):
        sys.stdout.flush()

def some_task():
    with settings(user = 'root'):
        run('./task_with_progress_bar.out', stdout = FixProgress())

这对问题中的 c 程序工作正常。

如果可以更改输出进度条的c文件的源代码,就可以使用isatty()测试stdin是否为tty。如果为 false,您可以将进度条输出抑制为仅在某些值处更新,即 25 的间隔。

http://linux.die.net/man/3/isatty