如何对含ANSI颜色代码的列表进行分栏排版?
带ANSI颜色输出的双栏分栏解决方案
问题核心
column、pr这类工具会将ANSI转义序列计入文本长度,导致实际显示的字符长度与工具计算值不符,最终出现条目上下偏移、对齐失效的问题。要解决这个问题,必须先剥离ANSI序列计算真实文本长度,再结合原始颜色信息重新排版。
可用脚本方案
1. Zsh自定义函数方案
利用Zsh的参数扩展实现ANSI序列清理,结合终端宽度自适应分栏:
color_column() { local lines=() line cleaned_line # 读取所有带颜色的输出行 while IFS= read -r line; do lines+=("$line") done local total_lines=${#lines[@]} # 计算双栏每栏的宽度,适配当前终端 local col_width=$(( (COLUMNS + 1) / 2 )) local half_lines=$(( (total_lines + 1) / 2 )) for ((i=0; i<half_lines; i++)); do # 清理当前行的ANSI转义序列,获取真实文本长度 cleaned_line=${lines[i]//$'\e'\[[0-9;]*m/} local padding=$(( col_width - ${#cleaned_line} )) # 输出当前行并补全空格,再输出右侧对应行(如果存在) printf "%s%${padding}s" "${lines[i]}" " " (( i + half_lines < total_lines )) && echo "${lines[i+half_lines]}" || echo done }
使用方式:
# 适配ls带颜色输出 ls -1 --color=always | color_column # 适配exa带颜色输出 exa -1 --color=always | color_column # 适配fd输出 fd . | color_column
2. Awk通用脚本方案
编写Awk脚本统一处理ANSI序列,实现跨Shell的分栏逻辑:
#!/usr/bin/awk -f # 清理字符串中的ANSI转义序列 function strip_ansi(str) { gsub(/\033\[[0-9;]*m/, "", str) return str } BEGIN { # 获取终端宽度,默认80列 term_cols = ENVIRON["COLUMNS"] ? ENVIRON["COLUMNS"] : 80 col_width = int((term_cols + 1) / 2) } # 存储原始行和清理后的行 { raw_lines[NR] = $0 clean_lines[NR] = strip_ansi($0) } END { total_lines = NR half_lines = int((total_lines + 1) / 2) for (i=1; i<=half_lines; i++) { # 计算需要补充的空格数 pad_len = col_width - length(clean_lines[i]) printf "%s%*s", raw_lines[i], pad_len, " " # 输出右侧对应行 if (i + half_lines <= total_lines) { print raw_lines[i + half_lines] } else { print "" } } }
使用步骤:
- 将脚本保存为
color_col.awk - 赋予执行权限:
chmod +x color_col.awk - 调用方式:
ls -1 --color=always | ./color_col.awk exa -1 --color=always | ./color_col.awk fd . | ./color_col.awk
3. ls原生双栏简化方案
如果仅需处理ls的带颜色输出,可直接使用其原生双栏参数,无需额外脚本:
ls --color=always -C
注意:该方案仅适配ls,无法用于fd或exa。
内容的提问来源于stack exchange,提问作者psprint
相关产品推荐
相关产品推荐

