0

I have a file which has many lines, each consisting of a comma-separated list. I'd like to sort each of these lines.

If I had a single line, it would be easy:

<file tr ',' '\n' | sort | tr '\n' ','

But if I do this on my file it lumps together all the lines which I don't want. How do I restrict this?

Charles
  • 11,269
  • 13
  • 67
  • 105

3 Answers3

3

It is (fairly) easy in Perl:

#!/usr/bin/env perl
use strict;
use warnings;

$, = ",";

while (<>)
{
    chomp;
    my @fields = split /,/;
    my @sorted = sort(@fields);
    $sorted[scalar(@sorted)-1] .= "\n";
    print @sorted;
}

The trickiness involves saving the sorted array so that the newline can be added to the last element of the array, so that you don't get lines ending with a comma. If that doesn't matter, then it is more compact — replace the last three lines of the loop with:

    print sort(@fields), "\n";

Input

x,b,z,a,c,e,f,g,d
3,19,12,17,16,19,18,17,20,16

Output

a,b,c,d,e,f,g,x,z
12,16,16,17,17,18,19,19,20,3

Compact code

It being Perl, there are ways to compress it:

perl -l -p -a -F, -e '$_ = join(",", sort(@F))' 

That's:

  • -l autochomp and handle newlines.
  • -p automatically read each input line, process it with the script, and print after each line.
  • -a split input lines into array F based on field separator.
  • -F, the field separator is a comma.
  • -e is followed by the program.
  • The program sets the default variable, $_, to the comma-joined list of sorted values in array F.

Perl handles the rest.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
1

You'd need to do it line-by-line. Use a loop:

while read -r line; do
  echo "${line}" | tr ',' '\n' | sort | tr '\n' ','
done < file

(Saying <file tr ',' '\n' would replace the commas with newlines in the entire file.)

devnull
  • 118,548
  • 33
  • 236
  • 227
  • 4
    That's expensive if there are many lines — 3 full fledged processes plus an echo per line. For a one-off on not too large files, it is fine, but for large-scale work… – Jonathan Leffler Mar 26 '14 at 07:30
1

You can avoid excessive piping and do all the sorting in GNU awk:

awk '{split($0, a, ","); n=asort(a);
      for (i=1; i<=n; i++) printf "%s%s", a[i], (i<n)?OFS:RS}' OFS=, file
mklement0
  • 382,024
  • 64
  • 607
  • 775
anubhava
  • 761,203
  • 64
  • 569
  • 643