1

I have the data (test.txt) in the below format.

x: a
y: b

I need it in this format. (1st thing that comes before: is the header, after the space the value is data) (edited)

x,y  
a,b 

I can do like

cat test.txt | tr ": " '\n'

x
a

y
b

It just comes in the new line. Is there any way I can achieve the desired format?

Ulrich Eckhardt
  • 16,572
  • 3
  • 28
  • 55
Domica
  • 39
  • 4
  • 1
    Action you want to make is called (matrix) *transposition* – Daweo Oct 06 '21 at 12:25
  • 2
    This is not just transposing. It changes output field separator also. – anubhava Oct 06 '21 at 13:04
  • Duplicate of https://stackoverflow.com/q/1729824/1331399 – tripleee Dec 16 '21 at 13:46
  • 1
    Just FYI please!! As mentioned by @anubhava, its not for only transposing, its more than that including field separators while taking values in output, answers given in mentioned link are not covering that part there. So it can be taken as a reference but it's not duplicate IMHO. – RavinderSingh13 Dec 18 '21 at 03:40
  • Does this answer your question? [An efficient way to transpose a file in Bash](https://stackoverflow.com/questions/1729824/an-efficient-way-to-transpose-a-file-in-bash) – bad_coder Dec 18 '21 at 23:45

4 Answers4

3

How about the BSD tool rs:

# Remove colons
<infile tr -d : |

# Transpose input
rs -T           |

# Change the delimiter
tr -s ' ' ,

This question and it's answers might provide some other alternatives.

Thor
  • 45,082
  • 11
  • 119
  • 130
  • If you know a question is a duplicate, please vote to close it as such instead of answering it. – miken32 Dec 17 '21 at 19:54
2

This might work for you (GNU sed):

sed -E 'sed -E 'N;s/:\s*(.*)\n(.*):\s*/,\2\n\1,/' file

Append the following line and substitute using pattern matching.

potong
  • 55,640
  • 6
  • 51
  • 83
1

1st solution: With your shown samples, please try following awk program.

awk '
BEGIN{ OFS="," }
{
  for(i=1;i<=NF;i++){
    if(i==1){
      sub(/:$/,"",$i)
    }
    value[i]=(value[i]?value[i] OFS:"")$i
  }
}
END{
  for(i=1;i<=NF;i++){
    print value[i]
  }
}
' Input_file

Explanation: Adding detailed explanation for above.

awk '                        ##Starting awk program from here.
BEGIN{ OFS="," }             ##Setting OFS to comma in BEGIN section.
{
  for(i=1;i<=NF;i++){        ##Traversing through all fields here.
    if(i==1){                ##If its first field then do following.
      sub(/:$/,"",$i)        ##Substitute ending colon with NULL in 1st field.
    }
    value[i]=(value[i]?value[i] OFS:"")$i  ##Creating value with index of i and keep appending $i in it.
  }
}
END{                         ##Starting END block from here.
  for(i=1;i<=NF;i++){        ##Traversing through all fields here.
    print value[i]           ##Printing value with index of i here.
  }
}
' Input_file                 ##Mentioning Input_file name here.

2nd solution: In case your Input_file can have dynamic(not fixed) number of fields per lines then try following, which will print values till maximum number of field numbers.

awk '
BEGIN{ OFS="," }
{
  for(i=1;i<=NF;i++){
    if(i==1){
      sub(/:$/,"",$i)
    }
    value[i]=(value[i]?value[i] OFS:"")$i
  }
  nf=(nf>NF?nf:NF)
}
END{
  for(i=1;i<=nf;i++){
    print value[i]
  }
}
' Input_file
RavinderSingh13
  • 130,504
  • 14
  • 57
  • 93
1
$ cat tst.awk
BEGIN {
    FS = ": *"
    OFS = ","
}
{
    for (i=1; i<=NF; i++) {
        vals[NR,i] = $i
    }
}
END {
    for (i=1; i<=NF; i++) {
        for (j=1; j<=NR; j++) {
            printf "%s%s", vals[j,i], (j<NR ? OFS : ORS)
        }
    }
}

$ awk -f tst.awk test.txt
x,y
a,b
Ed Morton
  • 188,023
  • 17
  • 78
  • 185