Shell
Loading a higher level language takes time.
For a few lines, the shell itself may be a solution.
We can use the external command sort
, and of the command tr
. One is quite efficient in sorting lines and the other is effective to convert one delimiter to newlines:
#!/bin/bash
shsort(){
while IFS='' read -r line; do
echo "$line" | tr "$1" '\n' |
sort -n | paste -sd "$1" -
done <<<"$2"
}
shsort ' ' '10 50 23 42'
shsort '.' '10.1.200.42'
shsort ',' '1,100,330,42'
shsort '|' '400|500|404'
shsort ',' '3 b,2 x,45 f,*,8jk'
shsort '.' '10.128.33.6
128.17.71.3
44.32.63.1'
This need bash because of the use of <<<
only. If that is replaced with a here-doc, the solution is valid for posix.
This is able to sort fields with tabs, spaces or shell glob characters (*
, ?
, [
). Not newlines because each line is being sorted.
Change <<<"$2"
to <"$2"
to process filenames and call it like:
shsort '.' infile
The delimiter is the same for the whole file. If that is a limitation, it could be improved on.
However a file with just 6000 lines takes 15 seconds to process. Truly, the shell is not the best tool to process files.
Awk
For more than a few lines (more than a few 10's) it is better to use a real programming language. An awk solution could be:
#!/bin/bash
awksort(){
gawk -v del="$1" '{
split($0, fields, del)
l=asort(fields)
for(i=1;i<=l;i++){
printf( "%s%s" , (i==0)?"":del , fields[i] )
}
printf "\n"
}' <"$2"
}
awksort '.' infile
Which takes only 0.2 seconds for the same 6000 lines file mentioned above.
Understand that the <"$2"
for files could be changed back to <<<"$2"
for lines inside shell variables.
Perl
The fastest solution is perl.
#!/bin/bash
perlsort(){ perl -lp -e '$_=join("'"$1"'",sort {$a <=> $b} split(/['"$1"']/))' <<<"$2"; }
perlsort ' ' '10 50 23 42'
perlsort '.' '10.1.200.42'
perlsort ',' '1,100,330,42'
perlsort '|' '400|500|404'
perlsort ',' '3 b,2 x,45 f,*,8jk'
perlsort '.' '10.128.33.6
128.17.71.3
44.32.63.1'
If you want to sort a file change <<<"$a"
to simply "$a"
and add -i
to perl options to make the file edition "in place":
#!/bin/bash
perlsort(){ perl -lpi -e '$_=join("'"$1"'",sort {$a <=> $b} split(/['"$1"']/))' "$2"; }
perlsort '.' infile; exit
cut
supports arbitrary delimiters with its-d
option.4,325 comma 55 comma 42,430
would not occur, nor1.5 period 4.2
).