You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在脚本执行后有条件地清除其输出?

实现低依赖的脚本输出条件清除包装器

需求背景

我需要开发一个脚本包装器,让被包装的脚本在执行过程中实时输出状态信息,执行完成后根据返回码有条件清除其输出:

  • 脚本执行成功(返回码0):清除该脚本产生的所有输出,仅保留之前终端的内容
  • 脚本执行失败(返回码非0):保留所有输出,方便排查问题

典型场景比如docker build、npm install这类命令,执行时需要让用户看到进度,但成功后冗长的输出会占用终端空间,失败则需要保留错误信息。

现有方案的不足

用screen命令可以实现执行时看输出、结束后隐藏的效果:

screen docker build <ARGS>

但这种方式存在两个问题:

  1. 依赖screen工具,无法在无该工具的环境使用
  2. 脚本执行失败时,screen退出后无法保留错误输出,不符合需求

理想行为

运行my-wrapper <COMMAND>需满足:

  • 启动时不清除终端屏幕(避免像多数curses程序那样清屏)
  • 正确传递被包装命令的stdout和stderr,保持实时输出
  • 子进程终止后:
    • 返回码0:仅清除该脚本产生的输出
    • 返回码非0:保留所有输出(必要时重新打印)

Bash实现(无额外依赖)

利用终端ANSI控制码实现,完全依赖系统自带的Bash,无需额外安装工具:

#!/bin/bash

# 仅在终端环境下执行清除逻辑
if [[ -t 1 ]]; then
    # 获取当前光标起始行位置
    IFS=';' read -sdR -p $'\033[6n' row col
    start_row=$row

    # 执行传入的目标命令
    "$@"
    exit_code=$?

    # 成功时清除输出
    if [[ $exit_code -eq 0 ]]; then
        # 获取当前光标位置
        IFS=';' read -sdR -p $'\033[6n' current_row col
        # 计算需要回退的行数
        lines_up=$((current_row - start_row))
        # 回到起始行并清除后续所有内容
        echo -e "\033[${lines_up}A\033[J"
    fi

    exit $exit_code
else
    # 非终端环境(如管道、重定向),直接执行命令
    "$@"
    exit $?
fi

使用说明

  1. 将脚本保存为my-wrapper,赋予执行权限:chmod +x my-wrapper
  2. 使用方式:./my-wrapper docker build <ARGS>

Python实现(低依赖)

依赖系统自带的Python3(多数Linux/macOS系统预装),逻辑更健壮,兼容性更好:

#!/usr/bin/env python3
import os
import sys
import subprocess
import fcntl
import termios

def get_cursor_position():
    # 发送终端控制码请求光标位置
    sys.stdout.write('\033[6n')
    sys.stdout.flush()
    # 读取终端响应并解析
    buf = []
    while True:
        char = sys.stdin.read(1)
        buf.append(char)
        if char == 'R':
            break
    response = ''.join(buf)
    row_part, col_part = response.split(';')
    row = int(row_part.split('[')[1])
    col = int(col_part.split('R')[0])
    return row, col

def main():
    if len(sys.argv) < 2:
        print(f"用法: {sys.argv[0]} <命令> [参数...]", file=sys.stderr)
        sys.exit(1)

    if sys.stdout.isatty():
        try:
            start_row, _ = get_cursor_position()
        except Exception:
            # 获取光标位置失败,直接执行命令
            subprocess.run(sys.argv[1:])
            sys.exit()

        # 执行目标命令,实时输出
        process = subprocess.Popen(sys.argv[1:], stdout=sys.stdout, stderr=sys.stderr)
        exit_code = process.wait()

        if exit_code == 0:
            try:
                current_row, _ = get_cursor_position()
                lines_up = current_row - start_row
                # 回退到起始行并清除后续内容
                sys.stdout.write(f'\033[{lines_up}A\033[J')
                sys.stdout.flush()
            except Exception:
                # 清除失败不影响正常退出
                pass

        sys.exit(exit_code)
    else:
        # 非终端环境直接执行命令
        subprocess.run(sys.argv[1:])

if __name__ == '__main__':
    main()

使用说明

  1. 保存为my-wrapper.py,赋予执行权限:chmod +x my-wrapper.py
  2. 使用方式:./my-wrapper.py npm install

注意事项

  1. 若执行命令过程中用户手动滚动终端,清除逻辑可能会出错(因为基于屏幕光标位置计算,而非实际输出行数)
  2. 仅支持ANSI控制码兼容的终端(现代主流终端如xterm、iTerm2、GNOME Terminal均支持)
  3. 非终端环境(如命令输出被重定向到文件/管道)下,包装器会直接执行命令,不进行清除操作

内容的提问来源于stack exchange,提问作者frans

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 18:58:17