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

如何用AWK或Sed将非结构化数据转换为表格格式?

动态转换键值对数据为表格格式的Shell脚本实现

需求描述

输入数据为按Row分组的键值对格式,每个字段单独一行:

Row: 1
Name    :   Ajay
Age     :   45
Address :   zyx

Row: 2
Name    :   Ajay
Age     :   45
Address :   zyx

Row: 3
Name    :   Ajay
Age     :   45
Address :   zyx

Row: 4
Name    :   Ajay
Age     :   45
Address :   zyx

需要将其转换为带表头、分隔线的表格格式,且支持任意列名和列数:

Name       Age        Address    
-----      ----       -------    
Ajay       45         zyx        
Ajay       45         zyx        
Ajay       45         zyx        
Ajay       45         zyx        

原脚本存在的问题

你提供的脚本有以下核心问题:

  • 错误假设第一个Row下的所有字段在同一行,实际每个字段单独一行,导致只能提取到第一个列名
  • 缺少表头分隔线的生成逻辑
  • 循环中多次调用sed和awk,处理大文件时效率低下

改进后的脚本

#!/bin/bash

data_file="ab.txt"

# 提取第一个Row块中的所有列名
column_names=()
while IFS= read -r line; do
    if [[ "$line" =~ ^Row: ]]; then
        # 读取当前Row块内的所有字段行,直到空行
        while IFS= read -r field_line && [[ -n "$field_line" ]]; do
            # 提取字段名(去除前后空格)
            col_name=$(awk -F ':' '{gsub(/^[ \t]+|[ \t]+$/, "", $1); print $1}' <<< "$field_line")
            column_names+=("$col_name")
        done
        break  # 仅提取第一个Row的列名作为表头
    fi
done < "$data_file"

# 打印对齐的表头
printf "%-12s" "${column_names[@]}"
printf "\n"

# 打印表头分隔线(与列名长度匹配)
for name in "${column_names[@]}"; do
    printf "%-12s" "$(printf "%0.s-" $(seq 1 ${#name}))"
done
printf "\n"

# 一次性解析所有数据并打印表格行
awk -v col_count="${#column_names[@]}" '
    BEGIN { current_row = 0; field_pos = 0 }
    /^Row:/ { current_row++; field_pos = 0; next }
    /^[[:space:]]*$/ { next }  # 跳过空行
    {
        # 分割键值对,去除值的前后空格
        split($0, kv, /:[[:space:]]+/)
        gsub(/^[[:space:]]+|[[:space:]]+$/, "", kv[2])
        row_data[current_row][++field_pos] = kv[2]
        
        # 当收集完当前行所有字段后,打印整行
        if (field_pos == col_count) {
            for (i=1; i<=col_count; i++) {
                printf "%-12s", row_data[current_row][i]
            }
            printf "\n"
        }
    }
' "$data_file"

脚本说明

  1. 列名提取:通过循环读取文件,定位第一个Row块,逐行解析每个字段的名称并存储到数组,确保支持任意列数。
  2. 表头与分隔线:用printf的格式化输出实现列对齐,分隔线长度与对应列名长度一致。
  3. 数据解析:使用awk一次性处理整个文件,按Row分组收集数据,当某一行的所有字段收集完成后统一打印,提升处理效率。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 14:46:30