Question

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?

Was it helpful?

Solution

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.

OTHER TIPS

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.)

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
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top