Search code examples
unixawksedpaste

AWK or sed to print data in table format


I've data like below.

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

I wanted output like below.

Name    Age     Address
-----   ----    -------
Ajay    45      xyz
Ajay    45      xyz
Ajay    45      xyz
Ajay    45      xyz

Name, Age & Address columns are just for example, it should be anything and of any number. So command should dynamically read the columns and print and same way read data and print

I tried below code

#!/bin/bash

get_column_names() {
    # Extract column names from Row: 1 and Row: 2
    sed -n '/Row: 1/{n;p;q}' "$1" | awk -F '[:\t]' '{for(i=1;i<=NF;i+=2) print $i}'
}

print_header() {
    printf "%s\t" "$@"
    printf "\n"
}

data_file="ab.txt"

# Get col names
header=$(get_column_names "$data_file")

print_header $header

# Read data from file and print each row
max_row=$(grep -c "Row:" "$data_file")
for ((i=1; i<=$max_row; i++)); do
    sed -n "/Row: $i/{n;p;}" "$data_file" | awk -F '[:\t]' '{for(i=2;i<=NF;i+=2) printf "%s\t", $i; printf "\n"}'
done

Solution

  • You may use this awk:

    awk -v OFS="\t" -F '[[:blank:]]*:[[:blank:]]*' '
    NF && $1 != "Row" {
       row[++c] = $2
       if (!first)
          hdr[c] = $1
    }
    !NF {
       if (!first) {
          for (i=1; i<=c; ++i)
             printf "%s", hdr[i] (i < c ? OFS : ORS)
          for (i=1; i<=c; ++i) {
             gsub(".", "-", hdr[i])
             printf "%s", hdr[i] (i < c ? OFS : ORS)}
             first = 1
          }
          for (i=1; i<=c; ++i)
             printf "%s", row[i] (i < c ? OFS : ORS)
          c = 0
    }
    END {
       for (i=1; i<=c; ++i)
          printf "%s", row[i] (i < c ? OFS : ORS)
    }' file | column -t -s $'\t'
    
    Name  Age  Address
    ----  ---  -------
    Ajay  45   zyx
    Ajay  45   zyx
    Ajay  45   zyx
    Ajay  45   zyx