The trick is loop thru the data two lines at a time; storing the values to an array; then outputting a csv at the end (if you want you can print output in the if [ -z "$name" ]
block but then you loose the nice headers).
#!/bin/bash
declare -A cell
declare -A head
i=0
while read name
do
if [ -z "$name" ]
then
((i+=1))
else
head[$name]=$name
read value
cell[$i,$name]=$value;
fi
done < "${1:-/dev/stdin}"
printf "%-10s; " "${head[@]}"; echo
printf "%.0s----------; " ${head[@]}; echo
j=0
until [ $j -gt $i ]; do
for name in ${head[@]}
do
printf "%-10s; " "${cell[$j,$name]}"
done
echo
((j+=1))
done
The above script presumes the sets are separated by a single empty line and will return:
$ head data
head1
value1-1
head2
value2-1
head2
value2-2
$ ./csvgen.sh data
head2 ; head3 ; head1 ; head4 ;
----------; ----------; ----------; ----------;
value2-1 ; ; value1-1 ; ;
value2-2 ; value3-2 ; ; ;
value2-3 ; ; value1-3 ; value4-3 ;
How it works:
loop over each line of either a file or stdin.
while read name
do
# ...
done < "${1:-/dev/stdin}"
if [ -z "$name" ] # If the line has a length of zero the set has ended
then # so increse the set index by 1.
((i+=1))
else
head[$name]=$name # this array contains all the headers we have seen
read value # read the next line to $value
cell[$i,$name]=$value; # save $value in array indexed by set and header
fi
printf "%-10s; " "${head[@]}"; # print each header from
echo # the above wont end the line so echo for a "\n"
printf "%.0s----------; " ${head[@]}; # %.0s truncates the input to nothing
echo # printing only the '----------'
until [ $j -gt $i ]; do # for each set index
for name in ${head[@]} # loop thru the headers
do
printf "%-10s; " "${cell[$j,$name]}" # then print the values
done
echo # end each set with "\n"
((j+=1))
done