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.

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

2 Answers 2

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.

3
  • 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. Commented Mar 29, 2016 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 Commented Mar 30, 2016 at 1:53
  • 1
    Yes, I know that awk doesn't need cat. The actual list is generated from a jq query... Commented Mar 30, 2016 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
5
  • 1
    That's character position from the start of the string, right? I need character position from the end. I'll clarify the question. Commented Mar 29, 2016 at 14:34
  • @RogerLipscombe Yes..you just need rev then.. Commented Mar 29, 2016 at 14:36
  • @RogerLipscombe Check my edits.. Commented Mar 29, 2016 at 14:38
  • 1
    Hmm. That sorts foo10a (etc.) into the wrong place... Commented Mar 29, 2016 at 14:43
  • @RogerLipscombe Yes, it does..i think your best bet would be go with the first one (if you can).. Commented Mar 29, 2016 at 14:45

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.