Take the 2-minute tour ×
Ask Ubuntu is a question and answer site for Ubuntu users and developers. It's 100% free, no registration required.

I was looking at this question and I wondered if the following could be done from terminal. I did it in python, just want to see if it could be done from terminal, bash scripting or whatever.

Suppose I have a file that looks like so:

2,4,5,14,9
40,3,5,10,1

could it be sorted like so, by rows (lines)

2,4,5,9,14
1,3,5,10,40

or is it too complicated? I did it using python, I just want to know if it could be done so next time I might not use python. What I have done, is creating lists and sorting them.

share|improve this question
    
I asked it here because I saw the other question, if it should not be asked here feel free to close it or delete it –  Fischer Apr 13 at 23:08
5  
I added the missing comma between 5 and 14 in your input example. Based on your output, I assume that was a typo, please clarify if it was not. –  terdon Apr 14 at 4:51

8 Answers 8

up vote 5 down vote accepted

Here's another Perl approach:

perl -F, -lane 'print join ",",sort {$a<=>$b} @F' file.txt

And another shell/coreutils one (though personally, I prefer steeldriver's excellent answer which uses the same idea):

while read line; do 
    tr , $'\n' < <(printf -- "%s" "$line") | sort -g | tr $'\n' , | sed 's/,$/\n/';
done < file.txt
share|improve this answer
1  
Nice solution, I up-vote immediately –  Sylvain Pineau Apr 14 at 5:41
    
As is yours and as did I :) –  terdon Apr 14 at 5:45
    
I hate it when I receive too many good answers :) and when you have to pick one randomly, it's like asking myself "what do I like more, chocolate bars or icecream?" –  Fischer Apr 14 at 21:28

This should do about what you're looking for. It will read a file (test.txt) and create an output file (sorted.txt) with the sorted lines in the same order as they appear in the original file.

while read line; do j=$(echo "$line" | sed -e 's/,/\n/g' | sort -n); echo "$j" 
    | sed -e 's/ /,/g' >> sorted.txt; done < test.txt
share|improve this answer
    
did you note the space in the first line 2,4,5 14,9? –  Avinash Raj Apr 14 at 4:36
    
bad usage of cat! To operate on each line, do while read line; do ...; done < test.txt –  Fredrik Pihl Apr 14 at 7:30
    
@FredrikPhil: Thank you. I have edited my answer. –  jkt123 Apr 14 at 9:11

The only real difficulty in doing what you want using command-line scripting is that the available sort function expects to sort lines within a file, rather than fields within a line. To work around that, you could replace the field delimiters, line-by-line, with newlines prior to the sort function, then replace the newlines with delimiters again in each line after sorting.

There are a number of available text processing utilities which would allow you to do that (including sed, awk, or even the simple tr) however the bash shell itself can do a lot nowadays. Assuming you meant for the input to be comma-delimited (you have a mix of commas and whitespace delimiters in your example) you could do:

while read line; do 
  sorted=$(sort -g -- <<< "${line//,/$'\n'}")
  printf -- "${sorted//$'\n'/,}\n"
done < file

If you do need to handle space delimiters in the input, then you can add them as part of a character list [, ] for the input substring replacement:

while read line; do 
  sorted=$(sort -g -- <<< "${line//[, ]/$'\n'}")
  printf -- "${sorted//$'\n'/,}\n"
done < file

(note that the output remains strictly comma-delimited though).

share|improve this answer

python -c "your code here" input.txt

Or, if your program has multiple lines and eval() is too slow:

python yourprogram.py input.txt

This oneliner works:

python -c "for l in open('input.txt'):print(','.join(sorted(l.strip().split(','), key=int)))"
share|improve this answer
    
The OP is not looking for a python-based solution. –  i08in Apr 14 at 16:43
    
Yes he is: "just want to see if it could be done from terminal, bash scripting or whatever." –  Cees Timmerman Apr 14 at 17:01
    
Lol, you nailed it, then! –  i08in Apr 14 at 17:04

Using tr and sed

Similar in spirit to what jkt123 wrote:

while read i; do tr , \\n <<< $i | sort -n | tr \\n , | sed 's/,$//'; done

It iterates over the lines, and for each line replaces commas by newlines, sorts the resulting lines numerically, then turns newlines back to commas. The main problem is that this will end the whole result with a comma not a newline, which is addressed by that last sed. It strips the last comma and also implicitely adds a newline to its output.

Using bash arrays

Here is a different approach to deal with this “join with commas” issue:

while read i; do j=( $(tr , \\n <<< $i | sort -n) ); ( IFS=,; echo "${j[*]}"; ); done

Or written with line wraps:

while read i
do
   j=( $(tr , \\n <<< $i | sort -n) )
   ( IFS=,; echo "${j[*]}"; )
done

It uses a bash array to store the result of the sorted row, and makes use of the way bash expands arrays into string literals using the IFS special variable.

share|improve this answer

Here comes an awk solution,

while read -r line; do (echo $line | awk '{ n=split($1,a,","); asort(a); for(i=0;i<=n;i++) { print a[i];}}') | xargs | sed -e 's/ /,/g'; done < text.txt

Explanation:

  • awk '{ n=split($1,a,","); asort(a); for(i=0;i<=n;i++) { print a[i];}}'

    awk Splits the field 1 according to the delimiter , and store each value into the array a finally the top position is stored into the variable n. Next asort(a) function sort down the array values.Then the for loop inside the awk command prints the sorted values in the format of record by record.

  • xargs | sed -e 's/ /,/g'

    xargs combines all the rows into a single row.

  • sed -e 's/ /,/g'

    It replaces the spaces with commas ,

  • while read -r line;

    All the above awk,xargs,sed functions are done line by line with the help of while loop.

share|improve this answer

You can do this easily using perl

consider you have file text.txt

cat text.txt

1,5,7,8,3,6
10,34,67,1,2,0,5

Now the following perl code will sort the rows in text.txt

 perl -i -e 'while(<>){chomp; my @sorted = sort { $a <=> $b } split(",", $_); print join (",", @sorted); print "\n"}' text.txt

After sorting

cat text.txt

1,3,5,6,7,8
0,1,2,5,10,34,67
share|improve this answer
2  
You could shorten this significantly with perl -i -lne 'print join (",", sort {$a <=> $b} split(",", $_));' text.txt. The -n flag is the same as while(<>){} and the -l adds a \n to every print call and also activates implicit chomp(). –  terdon Apr 14 at 6:00

The shortest solution using a perl oneliner:

perl -ne 'print join(",", sort { $a <=> $b } split(/,|\n/))."\n"' text.txt
share|improve this answer
    
Heh, I'd left my answer open for a while and hadn't seen this, but not the shortest :P –  terdon Apr 14 at 5:39
1  
Je m'incline ;-) –  Sylvain Pineau Apr 14 at 5:41

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.