Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

INPUT:

$ cat a.txt 
1FOO2FOO3
4FOO5FOO5
2FOO1FOO9
$ 

OUTPUT:

$ cat a.txt | sort SOMEMAGIC
2FOO1FOO9
1FOO2FOO3
4FOO5FOO5
$ 

Question: How can I sort, if I have a several character long delimiter? ("FOO")?

In the example a.txt is sorted by second column.

Question is in general, numbers in a.txt could be anything.

share|improve this question
1  
Maybe in this case you can sort from the 5th columns: sort -k1.5n –  Stéphane Chazelas Jul 4 at 18:20

4 Answers 4

Try this:

$ perl -ane '
    push @h,[$_,(split(/FOO/))[1]];
    END {
        print map  { $_->[0] }
              sort {$a->[1] <=> $b->[1]}
              @h;
    }
' file
2FOO1FOO9
1FOO2FOO3
4FOO5FOO5

Explanation

  • Store each array ref [line, key] in array @h: [$_,(split(/FOO/))[1]]

  • When finish reading file:

    • Sort array ref in array @h by key sort {$a->[1] <=> $b->[1]}
    • Extract the original line from @h and print map { $_->[0] }
share|improve this answer
    
What's map { [$_->[0],$_->[1]] } for? It looks like it returns the same two elements in each listref. –  arielCo Jul 4 at 22:26
    
@arielCo: It's a waste line, forget to clear it. Thanks! –  cuonglm Jul 4 at 22:39

Use e.g. sed to replace the string with a one-character delimiter, sort by the column, and then replace the delimiter back again:

sed -e s/FOO/X/g a.txt | sort -k 2,2 -t X | sed -e s/X/FOO/g 

This assumes that there is a character that you know doesn't appear in the input. A control character would be a common candidate, but you need to make a choice based on your knowledge of the input format.

share|improve this answer
    
That stops working when the 'fields' contain the temporary delimiter (e.g. 2FOOXFOO9). Of course, maybe you trust your knowledge of the input. –  arielCo Jul 4 at 22:24
    
The person would obviously have to check the input before choosing the new delimiter. –  Jenny D Jul 5 at 4:57

Assuming your fields are numeric, GNU sort's version sorting might help. Set the delimiter to F so that the trailing OO from FOO goes into field 2 and field 2 is seen by sort as containing values OO2, OO5 and OO1. Specifying version-sorting on field 2 ensures that the non-numeric prefix OO is ignored and output is ordered by the trailing numeric portions of field 2

sort -k2,2V -t 'F' a.txt
2FOO1FOO9
1FOO2FOO3
4FOO5FOO5

Alternately with GNU awk, if you tolerate the overhead of an in-memory solution:

awk -F'FOO' '{a[$2]=$0};END{asort(a, b, "@ind_num_asc");
for (i in b) print b[i]}' a.txt
2FOO1FOO9
1FOO2FOO3
4FOO5FOO5
share|improve this answer

I think you need not focus on the delimiter so much as you should the sort -keys. You can specify a character range for your keys.

info sort

...given the input line ' foo bar', sort breaks it into fields ' foo' and ' bar'. The field separator is not considered to be part of either the field preceding or the field following, so with 'sort -t " "' the same input line has three fields: an empty field, 'foo', and 'bar'. However, fields that extend to the end of the line, as '-k 2', or fields consisting of a range, as '-k 2,3', retain the field separators present between the endpoints of the range.

And as Stephane has commented, this also applies vice-versa - you can sort on only a slice of a field with a byte range, and even on multiple slices of the same field with multiple keys. So in your case you can use the same field with different ranges multiple times. See?

sort -k1.5n -k1.1n --debug <<\DATA
1FOO2FOO3
4FOO5FOO5
2FOO1FOO9
DATA
sort: using simple byte comparison
sort: leading blanks are significant in key 1; consider also specifying 'b'
sort: key 1 is numeric and spans multiple fields
sort: key 2 is numeric and spans multiple fields
2FOO1FOO9
    _
_
_________
1FOO2FOO3
    _
_
_________
4FOO5FOO5
    _
_
_________

That instructs sort to sort on the primary key beginning with the 5th byte in field 1 and extending to field 1's end, and secondarily to sort from the 1st byte in field one to field one's end. The --debug option is very helpful when trying to sort sort, as I hope the above demonstrates. But here it is without debug:

sort -k1.5n -k1.1n <<\DATA        
1FOO2FOO3
4FOO5FOO5
2FOO1FOO9
DATA

###OUTPUT###
2FOO1FOO9
1FOO2FOO3
4FOO5FOO5

If you wanted to sort only a single character for each you'd need to close your ranges. In the above example -k1.5n works from byte 5 to field end because the key specification works like:

 -k[begin field].[first byte in key],[end field].[last byte in key]

So, while the results are identical for this case, you can close each field range on the same byte with which you open it like:

sort -k1.5,1.5n -k1.1,1.1n

and thereby only sort by a single byte for each key.

share|improve this answer

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.