sort pipe delimited file with empty columns - linux

I am getting an issue using sort and I believe it is due to an empty column before the column I am sorting on. I ran a sort on the file sort -n -t'|' -k4 testme -o testedsort, here's the output of testedsort
N|N||+006422931|+000359029|OVERLAY
N|N|A|+000000020|+000000000|580
N|N|A|+000000020|+000000020|705
N|N|A|+000008035|+000000000|800
N|N|A|+000009701|+000000000|723
N|N|A.|+000009701|+001569434|742
N|N|A|+000009701|+001569434|742
N|N|A|+000013723|+000000000|DLORGN
N|N|A|+000020963|+000000020|729
N|N|A|+000022110|+004066830|GRANT
It appears that everything is fine except the first record, and the only thing peculiar about it is that we have an empty column. Has anyone seen this and are there any suggestions on how to fix this?

Two things to fix
Assuming you are looking to sort by the fourth field only, specify the sort key as -k4,4
To handle leading + sign in numbers, use -g instead of -n (possibly GNU sort-specific)
sort -k4,4g -t'|' testme -o testedsort

Related

unix sort by single column only

I have a file of numbers seperated by comma. I want to sort the list by columns 2 only. my expecation is that lines wil lbe sorted by only the second columns and not by additional columns. I am not looking to sort by multiple keys. I know how to sort by a single key. My question here is why when i am sotin giving start POS and end POS as column 2 why is it also sorting columns 3?
FILE
cat chris.num
1,5,2
1,4,3
1,4,1
1,7,2
1,7,1
AFTER SORT
sort -t',' -k2,2 chris.num
1,4,1
1,4,3
1,5,2
1,7,1
1,7,2
However my expected output is
1,4,3
1,4,1
1,5,2
1,7,2
1,7,1
So i thought since i give the start and end key as -k2,2 that it would sort only based on this column but it seems to be sorting the other columns too. how can i get this to sort only by column 2 and not by others
From the POSIX description of sort:
Except when the -u option is specified, lines that otherwise compare equal shall be ordered as if none of the options -d, -f, -i, -n, or -k were present (but with -r still in effect, if it was specified) and with all bytes in the lines significant to the comparison. The order in which lines that still compare equal are written is unspecified.
So in your case, when two lines have the same value in the second column and thus are equal, the entire lines are then compared to get the final ordering.
GNU sort (And possibly other implementations, but it's not mandated by POSIX) has the -s option for a stable sort where lines with keys that compare equal appear in the same order as in the original, which is what it appears you want:
$ sort -t, -s -k2,2n chris.num
1,4,3
1,4,1
1,5,2
1,7,2
1,7,1

Bash sort -nu results in unexpected behaviour

A colleague of mine noticed some odd behaviour with the sort command today, and I was wondering if anyone knows if the output of this command is intentional or not?
Given the file:
ABC_22
ABC_43
ABC_1
ABC_1
ABC_43
ABC_10
ABC_123
We are looking to sort the file with numeric sort, and also make it unique, so we run:
sort file.txt -nu
The output is:
ABC_22
Now, we know that the numeric sort won't work in this case as the lines don't begin with numbers (and that's fine, this is just part of a larger script), but I would have expected something more along the lines of:
ABC_1
ABC_10
ABC_123
ABC_22
ABC_43
Does anyone know why this isn't the case? The sort acts as one would expect if given just the -u or -n options individually.
With -n, an empty number is zero:
Sort numerically. The number begins each line and consists of optional
blanks, an optional ‘-’ sign, and zero or more digits possibly
separated by thousands separators, optionally followed by a
decimal-point character and zero or more digits. An empty number is
treated as ‘0’.
All these lines have an empty number at the start of the line, so they are all zero for sort's numerical uniqueness. If you'd started each line with the same number, say 1, the effect would be the same. You should specify the field containing the numbers explicitly, or use version sort (-V):
$ sort -Vu foo
ABC_1
ABC_10
ABC_22
ABC_43
ABC_123
You are missing specifying the de-limit on the second field of GNU sort as
sort -nu -t'_' -k2 file
ABC_1
ABC_10
ABC_22
ABC_43
ABC_123
The flag -n for numerical sort, -u for unique lines and the key part is to set de-limiter as _ and sort on the second field after _ done by -k2.

Differences between Unix commands for Sorting CSV

What's the difference between:
!tail -n +2 hits.csv | sort -k 1n -o output.csv
and
!tail -n +2 hits.csv | sort -t "," -k1 -n -k2 > output.csv
?
I'm trying to sort a csv file by first column first, then by the second column, so that lines with the same first column are still together.
It seems like the first one already does that correctly, by first sorting by the field before the first comma, then by the field following the first comma. (breaking ties, that is.)
Or does it not actually do that?
And what does the second command do/mean? (And what's the difference between the two?) There is a significant difference between the two output.csv files when I run the two.
And, finally, which one should I use? (Or are they both wrong?)
See also the answer by #morido for some other pointers, but here's a description of exactly what those two sort invocations do:
sort -k 1n -o output.csv
This assumes that the "fields" in your file are delimited by a transition from non-whitespace to whitespace (i.e. leading whitespace is included in each field, not stripped, as many might expect/assume), and tells sort to order things by a key that starts with the first field and extends to the end of the line, and assumes that the key is formatted as a numeric value. The output is sent explicitly to a specific file.
sort -t "," -k1 -n -k2
This defines the field separator as a comma, and then defines two keys to sort on. The first key again starts at the first field and extends to the end of the line and is lexicographic (dictionary order), not numeric, and the second key, which will be used when values of the first key are identical, starts with the second field and extends to the end of the line, and because of the intervening -n, will be assumed to be numeric data as well. However, because your first key entails the entire line, essentially, the second key is not likely to ever be needed (if the first key of two separate lines is identical, the second key most likely will be too).
Since you didn't provide sample data, it's unknown whether the data in the first two fields is numeric or not, but I suspect you want something like what was suggested in the answer by #morido:
sort -t, -k1,1 -k2,2
or
sort -t, -k1,1n -k2,2n (alternatively sort -t, -n -k1,1 -k2,2)
if the data is numeric.
First off: you want to remove the leading ! from these two commands. In Bash (and probably others since this comes from csh) you are otherwise referencing the last command that contained tail in your history which does not make sense here.
The main difference between your two versions is that in the first case you are not taking the second column into account.
This is how I would do it:
tail -n +2 hits.csv | sort -t "," -n --key=1,1 --key=2,2 > output.csv
-t specifies the field separator
-n turns on numerical sorting order
--key specifies the fields that should be used for sorting (in order of precedence)

Descending order sort for very small numbers

I have my input file as :
Helguson 1.11889675673e-06
CAPTION_spot 1.37407731642e-07
Earning 1.20657023177e-06
340km 6.82228429758e-07
Mortimer 3.08700799033e-07
yellow 6.26784196571e-06
four 0.000271117940104
Pronk 5.79848408861e-07
jihad 3.25632057648e-07
I want to sort in descending order of the second column and hence, I tried using the linux command:
sort -k2 -nr input.txt > output.txt
My output is generated as:
340km 6.82228429758e-07
yellow 6.26784196571e-06
Pronk 5.79848408861e-07
jihad 3.25632057648e-07
Mortimer 3.08700799033e-07
CAPTION_spot 1.37407731642e-07
Earning 1.20657023177e-06
Helguson 1.11889675673e-06
four 0.000271117940104
It is not sorting properly. How to resolve this? Please help.
You need to include the -g option in sort. Otherwise it sorts in alphanumeric order, but with -g it converts it to a number first and then sorts.

how to sort based on a column but uniq based on another column?

He all,
I have a file having some columns. I would like to do sort for column 2 then apply uniq for column 1. I found this post talking about sort and uniq for the same column but my problem is a little bit different. I am thinking of using something using sort and uniq but don't know how. Thanks.
You can use pipe, however it's not in place.
Example :
$ cat initial.txt
1,3,4
2,3,1
1,2,3
2,3,4
1,4,1
3,1,3
4,2,4
$ cat initial.txt | sort -u -t, -k1,1 | sort -t, -k2,2
3,1,3
4,2,4
1,3,4
2,3,1
Result is sorted by key 2, unique by key 1. note that result is displayed on the console, if you want it in a file, just use a redirect (> newFiletxt)
Other solution for this kind of more complex operation is to rely on another tool (depending on your preferences (and age), awk, perl or python)
EDIT:
If i understood correctly the new requirement, it's sorted by colum 2, column 1 is unique for a given column 2:
$ cat initial.txt | sort -u -t, -k1,2 | sort -t, -k2,2
3,1,3
1,2,3
4,2,4
1,3,4
2,3,1
1,4,1
Is it what you expect ? Otherwise, I did not understand :-)
uniq needs the data to be in sorted order to work, so if you sort on second field and then apply uniq on first field, you won't get correct result.
You may want to try
sort -u -t, -k1,1 filename | sort -t, -k2,2
Just to be sure that I got what you mean correctly. You want to sort a file based on the second column in the file. Then you want to remove duplicates from the first column (another way of saying applying uniq to column one!). cool, to do this, you need to perform three tasks:
sort the column on which uniq is going to be applied (since uniq can
work only on sorted input).
apply uniq on the sorted column.
sort the output based on the values in column two.
Using pipes: The command is
sort -t ',' -k1 fileName| awk '!x[$1]++' | sort -t ',' -k2
Note that you cannot specify the first field in uniq, you can use the -f switch to jump the first n fields. Hence, I used awk to replace uniq.
I used this
sort -t ',' -nk2
here sorts
1,2
2,5
3,1
to
3,1
1,2
2,5

Resources