Trouble pipelining grep into a sort - linux

I have data in file in the form:
Torch Lake township | Antrim | 1194
I'm able use grep to look for keywords and pipe that into a sort but the sort isn't behaving how I intendended
This is what I have:
grep '| Saginaw' data | sort -k 5,5
I would like to be able to sort by the numerical value in the last column but it currently isn't and I'm unsure what I'm actually doing wrong.

A few things seem to be bogging you down.
First, the vertical bar can be a special character in grep. It means OR. Ex:
A|B
could be interpreted as A or B, and not A vertical bar B.
To correct that, you need to tell grep to interpret the | as a non-special character. To do that, escape it, like this:
grep '\| Saginaw' data
or, simply remove it altogether, if you data format allows that.
Second, the sort command needs to know what your column separator is. By default, it uses a space character (Actually, it's any white space). sort -k 5,5 actually says "sort on the 5th word"
To specify that your column separator is actually the vertical bay, use the -t option:
sort -t'|' -k 5,5
alternately,
sort --field-separator='|' -k 5,5
Third, You've got a bit of a sticky wicket now. Your data is formatted as:
Field1 | Field2 | Field3
...and not...
Field1|Field2|Field3
You may have issues with that additional space. Or maybe not. If all of your data has EXACTLY the same white-space, you'll be fine. If some have a single space, some have 2 spaces, and others have a tab, your sort will get jacked up.
Fourth, sorting by numbers may not be intuitive for you. The number 10 comes after the number 1 and before the number 2.
To sort the way you think it ought to be, where 10 comes after 9, use the option -n for numeric sort.
grep '\| Saginaw' data | sort -t'|' -n -k 5,5
The entire filed #5 will be sorted. Thus, 10 Abbington will come before 10 Andover.

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)

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

How to sort by two fields (one numeric, one string) at the same time using the built in "sort" program?

I have a file, lets say "bigfile", with tabular data of the following form,
a1 b2 a3 1
b1 a2 c3 0
... and so on.
I want to use the built-in "sort" program on my Linux machine so sort this file by the fourth field(numeric) and then by the first field at the same time. I went through the man pages a couple of times and all I could come up with was,
sort -n -k4,4 -k1,1 bigfile
Is there a way to make "sort" do what I want or I have to write my own custom program?
Thank you.
From the manpage:
POS is F[.C][OPTS], where F is the
field number and C the character
position in the field; both are origin
1. If neither -t nor -b is in effect,
characters in a field are counted from
the beginning of the preceding
whitespace. OPTS is one or more
single-letter ordering options,
which override global ordering options
for that key. If no key is given, use
the entire line as the key.
sort -k4,4n -k1,1 bigfile ought to do it.
Another option would be sort -k1,1 bigfile | sort --stable -n -k4,4 The stable sort means that ties on the 4th field are resolved by the initial position, which is set by the first pass of sort to be first field.

Resources