在 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 的间隔。
我正在使用 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 的间隔。