3

I have a file that looks like this:

foo03a
foo02b
quux01a
foo01a
foo02a
foo01b
foo03b
quux01b

I'd like it ordered by the last character (so a and b appear together) and then by the preceding number, and then by the prefix (though this is not essential). So that it results in:

foo01a
quux01a
foo02a
foo03a
foo01b
quux01b
foo02b
foo03b

It actually doesn't particularly matter where quux01a and quux01b appear, as long as they're in the relevant group -- they can appear as shown, before foo01b, or after foo03b.

Why? These are server names used in a blue/green deployment, so I want the 'A' servers together, then the 'B' servers.

I found the -k switch to GNU sort, but I don't understand how to use it to specify a particular character, counting from the end of the string.

I tried cat foos | rev | sort | rev, but that sorts foo10a and foo10b (when we count up that far) into the wrong place.

  • cat foos |rev | sort |rev foo01a foo02a foo03a foo01b foo02b foo03b this is what I'm getting. Isn't it what you want ? – Pacifist Mar 29 '16 at 14:22
  • sort -k1.6 -k1.4,1.5n -k1.1,1.3 file – cuonglm Mar 29 '16 at 14:26
2

I found a solution using GNU awk's match function:

cat foos | \
  gawk 'match($0, /([^0-9]+)([0-9]+)([^0-9]+)/, a) {print a[3], a[2], $0}' | \
  sort | cut -d' ' -f3

The gawk command uses regex captures to generate the sort key, so that I end up with the following:

a 03 foo03a
b 02 foo02b

...etc.

Run that through sort, cut for the fields I want. Done.

|improve this answer|||||
  • awk doesn't need cat, just so you know. I'd use something like sed 's/\(.*\)\([0-9][0-9]*\)/\1\x02\2\x02/' infile | sort -t $'\002' -k3,3 -k2,2n -k1,1 | tr -d $'\002' here. – don_crissti Mar 29 '16 at 17:15
  • can also be done with any version of sed, using basic regular expressions: sed -e 's/\(^[^0-9]*\)\([0-9]\+\)\(.\)$/\3 \2 \1\2\3/' foos | sort | cut -d' ' -f3 – cas Mar 30 '16 at 1:53
  • 1
    Yes, I know that awk doesn't need cat. The actual list is generated from a jq query... – Roger Lipscombe Mar 30 '16 at 8:44
1

You can sort by character position (indicated by number after .) of field (here field 1):

sort -k1.6 -k1.4,1.5n -k1.1,1.3 file.txt 

Example:

$ cat file.txt 
foo03a
foo02b
foo01a
foo02a
foo01b
foo03b

$ sort -k1.6 -k1.4,1.5n -k1.1,1.3 file.txt 
foo01a
foo02a
foo03a
foo01b
foo02b
foo03b

Reverse way, using rev:

$ rev file.txt | sort -k1.1,1.1 -k1.2,1.3n -k1.4 | rev
foo01a
foo02a
foo03a
foo01b
foo02b
foo03b
|improve this answer|||||
  • 1
    That's character position from the start of the string, right? I need character position from the end. I'll clarify the question. – Roger Lipscombe Mar 29 '16 at 14:34
  • @RogerLipscombe Yes..you just need rev then.. – heemayl Mar 29 '16 at 14:36
  • @RogerLipscombe Check my edits.. – heemayl Mar 29 '16 at 14:38
  • 1
    Hmm. That sorts foo10a (etc.) into the wrong place... – Roger Lipscombe Mar 29 '16 at 14:43
  • @RogerLipscombe Yes, it does..i think your best bet would be go with the first one (if you can).. – heemayl Mar 29 '16 at 14:45

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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