Home > Software design >  Convert single column to multiple, ensuring column count on last line
Convert single column to multiple, ensuring column count on last line

Time:01-09

I would like to use AWK (Windows) to convert a text file with a single column to multiple columns - the count specified in the script or on the command line.

This question has been asked before but my final data file needs to have the same column count all the way.

Example of input:

L1
L2
L3
L4
L5
L6
L7

split into 3 columns and ";" as a separator

L1;L2;L3
L4;L5;L6
L7;;        <<< here two empty fields are created after end of file, since I used just one on this line.

I tried to modify variants of the typical solution given: NR%4 {printf $0",";next} 1; and a counter, but could not quite get it right.

I would prefer not to count lines before, thereby running over the file multiple times.

CodePudding user response:

You may use this awk solution:

awk -v n=3 '{
   sub(/\r$/, "")   # removes DOS line break, if present
   printf "%s", $0(NR%n ? ";" : ORS)
}
END {
   # now we need to add empty columns in last record
   if (NR % n) {
      for (i=1; i < (n - (NR % n));   i)
         printf ";"
      print ""
   }
}' file

L1;L2;L3
L4;L5;L6
L7;;

CodePudding user response:

With your shown samples please try following awk code. Using xargs awk combination to achieve the outcome needed by OP.

xargs -n3 < Input_file | 
awk -v OFS=";" '{if(NF==1){$0=$0";;"};if(NF==2){$0=$0";"};$1=$1} 1'

CodePudding user response:

For an awk I would do:

awk -v n=3 '
{printf("%s%s", $0, (NR%n>0) ? ";" : ORS)}
END{
    for(i=NR%n; i<n-1; i  ) printf(";")
    printf ORS
}' file 

Or, an alternative awk:

awk -v n=3 -v OFS=";" '
{ row=row ? row FS $0 : $0 }           # build row of n fields
!(NR%n) {$0=row; NF=n; print; row="" } # split the fields sep by OFS
END { if (NR%n) { $0=row; NF=n; print } }  # same
' file  

Or you can use ruby if you want more options:

ruby -le '
n=3
puts $<.read.
    split($/).
    each_slice(n).
    map{|sl| sl.fill(sl.size...n) { "" }; sl.join(";") }.
    join($\) # By using $\ and $/ with the -l the RS and ORS is set correctly for the platform
' file

Or, realize that paste is designed to do this:

paste -d';' - - - <file 

(Use a - for each column desired)

Any of those prints (with n=3):

L1;L2;L3
L4;L5;L6
L7;;

(And work correctly for other values of n...)

  • Related