How to sort characters after a period - sorting

Need help on how to sort characters or numbers after a period(.)
test2.rod1
test1.rod1
test3.rod1
test1.mor2
test2.mor2
test3.mor2
zbcd1.abc1
abcd2.abc1
dbcd3.abc1
I would like the sort result anything after the period (.). Result should be something like below.
abcd2.abc1
dbcd3.abc1
zbcd1.abc1
test1.mor2
test2.mor2
test3.mor2
test2.rod1
test1.rod1
test3.rod1

If you're using a system with Unix like utilities such as MacOS, Linux, BSD, etc, then you can use the system sort command. The secret is to specify the field delimiter, which in your case is a period. The argument is either -t or --field-separator. So the following should work:
sort -t. -k 2 test.dat
Assuming that your data is in a file called test.dat

Related

Unix sort: sort by specific character following another character

I have a file that contains information in the following form:
"dog/3/cat/6/fish/2/78/90"
(we'll not worry about the last two values here)
Is it possible to sort the contents of the file by the numeric value after the odd numbered slashes with the unix sort command?
For instance, the output might look like this:
dog/4/house/3/frog/89/100
dog/3/mouse/2/chicken/12/68/80
dog/2/cat/5/bird/12/77/90
This should give you what you want, I think:
sort -t/ -k2,2nr -k4,4nr -k6,6nr

Unexpected bash sort behavior

If I create a text file containing the following lines:
>TESTTEXT_10000000
>TESTTEXT_1000000
>TESTTEXT_10000002
>TESTTEXT_10000001
and perform sort myfile, my output is
>TESTTEXT_1000000
>TESTTEXT_10000000
>TESTTEXT_10000001
>TESTTEXT_10000002
However, if I append /1 and /2 to my lines the sort output changes drastically, and I do not know why.
Input:
>TESTTEXT_10000000/1
>TESTTEXT_1000000/1
>TESTTEXT_10000002/1
>TESTTEXT_10000001/1
Output:
>TESTTEXT_10000000/1
>TESTTEXT_1000000/1
>TESTTEXT_10000001/1
>TESTTEXT_10000002/1
Input:
>TESTTEXT_10000000/2
>TESTTEXT_1000000/2
>TESTTEXT_10000002/2
>TESTTEXT_10000001/2
Output:
>TESTTEXT_10000000/2
>TESTTEXT_10000001/2
>TESTTEXT_1000000/2
>TESTTEXT_10000002/2
Is the forward slash being recognised as a seperator? using --field-sperator did not alter the behaviour. If so, why is 1000000/2 in between the 1000001/2 and 1000002/2 entries? Using the human sort, numeric sort or other options never brought about consistency. Can anyone help me out here?
:edit:
Because it seems to be relevant, considering the answers, the value of LC_ALL on this machine is en_GB.UTF-8
/ is before 0 in your locale. Using LC_ALL=C or other locale will properly not change anything.
In your use case you would properly be able to use -Version sort:
sort -V myfile
Alternative can you specify the separator and keys to sort on:
sort -t/ -k1,1 myfile

wbemcli: key/value pair output

If I use wbemcli to enumerate all the instances I get something similar to this:
wbemcli -nl -t -noverify ei 'https://aaa/aaa:aaa'
https://aaa/aaa:aaa.Version="",Vendor="",Name=""
-Version#=""
-Vendor#=""
-Name#=""
-Description=""
How can I call wbemcli to get only one item (i.e. the Name)? and not everything.
The -t option says:
-t
Append array ([]), reference (&) and key property (#) indicators to property names
but I wasn't able to utilize this in my favor.
Is there a way to retrieve this information in a key/value pair format?
Or maybe pipe the output into an array or something from which I can grab only what I need?
When I drop the output into an array all the data is stored in the first element ${a[0]}.
EDIT
Here's an output example:
$ wbemcli -nl -t -noverify ei 'https://user:pw#000.000.000.000:0000/root/aaa:AA_AaaAaaaAaaaa'
000.000.000.000:0000/root/aaa:AA_AaaAaaaAaaaa.ClassName="AA_AaaAaaaAaaaa",Name="123456a7ff890123"
-ClassName#="AA_AaaAaaaAaaaa"
-Name#="123456a7ff890123"
-Caption="aa aaa"
-Description="aa aa"
-ElementName="aa aaa aaaa"
-OperationalStatus[]=2
-HealthState=5
-CommunicationStatus=2
-DetailedStatus=1
-OperatingStatus=0
-PrimaryStatus=1
-EnabledState=5
-RequestedState=12
-EnabledDefault=2
-TransitioningToState=12
-PrimaryOwnerName="Uninitialized Contact"
-PrimaryOwnerContact="Uninitialized Contact"
The output is usually in this format.
If the query returns multiple objects they will be grouped and all will have the same members with their appropriate values.
http://linux.dell.com/files/whitepapers/WBEM_based_management_in_Linux.pdf has a number of examples which simply suggest to use grep to obtain the specific key and value you are looking for. There does not seem to be a way to directly query for a specific key within a result set.
Expanding on the comment by Etan Reisner, you could use something like
wbemcli <<query>> | grep -oP "^-$key=\K.*"
to obtain the value for the key named in $key, provided you have GNU grep which provides the -P option for Perl-compatible regular expressions (here, the \K "forget up through here" operator is useful). So for your specific example,
wbemcli -nl -t -noverify ei 'https://aaa/aaa:aaa' |
grep -oP '^-Name#=\K.*'
There is also a -dx option which produces XML output, which may be more robust if you are planning to write a major application on top of this protocol (but then perhaps you should be looking at a dedicated WBEM library such as the C or Java libraries listed in their wiki). It would not seem to be implausible to write a simple (e.g.) Python client to retrieve (part of?) the result tree and let you query or manipulate it locally, either.

unix sort -n -t"," gives unexpected result

unix numeric sort gives strange results, even when I specify the delimiter.
$ cat example.csv # here's a small example
58,1.49270399401
59,0.000192136419373
59,0.00182092924724
59,1.49270399401
60,0.00182092924724
60,1.49270399401
12,13.080339685
12,14.1531049905
12,26.7613447051
12,50.4592437035
$ cat example.csv | sort -n --field-separator=,
58,1.49270399401
59,0.000192136419373
59,0.00182092924724
59,1.49270399401
60,0.00182092924724
60,1.49270399401
12,13.080339685
12,14.1531049905
12,26.7613447051
12,50.4592437035
For this example, sort gives the same result regardless if you specify the delimiter. I know if I set LC_ALL=C then sort starts to give expected behavior again. But I do not understand why the default environment settings, as shown below, would make this happen.
$ locale
LANG="en_US.UTF-8"
LC_COLLATE="en_US.UTF-8"
LC_CTYPE="en_US.UTF-8"
LC_MESSAGES="en_US.UTF-8"
LC_MONETARY="en_US.UTF-8"
LC_NUMERIC="en_US.UTF-8"
LC_TIME="en_US.UTF-8"
LC_ALL=
I've read from many other questions (e.g. here, here, and here) how to avoid this behavior in sort, but still, this behavior is incredibly weird and unpredictable and has caused me a week of heartache. Can someone explain why sort with default environment settings on Mac OS X (10.8.5) would behave this way? In other words: what is sort doing (with local variables set to en_US.UTF-8) to get that result?
I'm using
sort 5.93 November 2005
$ type sort
sort is /usr/bin/sort
UPDATE
I've discussed this on the gnu-coreutils list and now understand why sort with english unicode default locale settings gave the output it did. Because in English unicode, the comma character "," is considered a numeric (so as to allow for comma's as thousand's (or e.g. hundreds) separators), and sort defaults to "being greedy" when it interprets a line, it read the example numbers as approximately
581.491...
590.000...
590.001...
591.492...
600.001...
601.492...
1213.08...
1214.15...
1226.76...
1250.45...
Although this was not what I had intended and chepner is right that to get the actual result I want, I need to specify that I want sort to key on only the first field. sort defaults to interpreting more of the line as a key rather than just the first field as a key.
This behavior of sort has been discussed in gnu-coreutil's FAQ, and is further specified in the POSIX description of sort.
So that, as Eric Blake on the gnu-coreutil's list put it, if the field-separator is also a numeric (which a comma is) then "Without -k to stop things, [the field-separator] serves as BOTH a separator AND a numeric character - you are sorting on numbers that span multiple fields."
I'm not sure this is entirely correct, but it's close.
sort -n -t, will try to sort numerically by the given key(s). In this case, the key is a tuple consisting of an integer and a float. Such tuples cannot be sorted numerically.
If you explicitly specify which single keys to sort on with
sort -k1,1n -k2,2n -t,
it should work. Now you are explicitly telling sort to first sort on the first field (numerically), then on the second field (also numerically).
I suspect that -n is useful as a global option only if each line of the input consists of a single numerical value. Otherwise, you need to use the -n option in conjunction with the -k option to specify exactly which fields are numbers.
Use sort --debug to find out what's going on.
I've used that to explain in detail your issue at:
http://lists.gnu.org/archive/html/coreutils/2013-10/msg00004.html
If you use
cat example.csv | sort
instead of
cat example.csv | sort -n --field-separator=,
then it would give correct output. Use this command, hope this is helpful to you.
Note: I tested with "sort (GNU coreutils) 7.4"

Sorting IP addresses in vim

I have just discovered the command :sort n in vim (how did I not know about that?!), which has almost done exactly what I need.
What I am trying to sort, though, is a long list of IP addresses (it's an "allow hosts" file to be Included into our apache config), and it would be nice for :sort n to be able to recognise that 123.45.6.7 should sort before 123.45.16.7 (for example).
Is it a safe assumption that I should be less OCD about it and not worry, because I'm not going to be able to do this without a mildly-complex sed or awk command or something?
To be clear, the rows all look something like:
Allow from 1.2.3.4
Allow from 5.6.7.8
Allow from 9.10.11.12
etc
Vim sort seems to be stable in practice (but it is not guaranteed). Therefore you can try:
:%sort n /.*\./
:%sort n /\.\d\+\./
:%sort n /\./
:%sort n
Which will sort by number after the last dot (* is greedy), then by number after the first dot following a dot and digits, then by number after the first dot, and last by the first number.
A straightforward way to achieve the correct sorting order without
relying on the stability of the sorting algorithm implemented by the
:sort command, is to prepend zeroes to the numbers within the IP
addresses, so that all of the components in them consist of exactly
three digits.
Prepend zeros to the single-digit and two-digit numbers:
:%s/\<\d\d\?\>/0&/g|%&&
Sort the lines comparing IP addresses as text:
:sort r/\(\d\{3}\)\%(\.\d\{3}\)\{3}/
Strip redundant leading zeros:
:%s/\<00\?\ze\d//g
To run all three steps as a single command, one can use the following
one-liner:
:%s/\<\d\d\?\>/0&/g|%&&|sor r/\(\d\{3}\)\%(\.\d\{3}\)\{3}/|%s/\<00\?\ze\d//g
I'm not a vim user so I can't offer a direct way to do it with builtin commands, however it's possible to replace a section of text with the output of it run through a command. So, a simple script like this could be used:
#!/usr/bin/python
import sys
input_lines = sys.stdin.readlines()
sorted_lines = sorted(input_lines,
key=lambda line: map(int, line.split()[-1].split('.')))
for line in sorted_lines:
sys.stdout.write(line)
See https://www.linux.com/learn/tutorials/442419-vim-tips-working-with-external-commands, section "Filtering text through external filters", which explains how you can use this as a filter within vim.
This script should do what you want and will work on any region where all the selected lines end in an IPv4 address.
You can use:
:%!sort -t . -k 1,1n -k 2,2n -k 3,3n -k 4,4n
-t . means use . as delimiter.
Then sort numerically from 4th column to 1st column.

Resources