I have a fixed-width-field file which I'm trying to sort using the UNIX (Cygwin, in my case) sort utility.
The problem is there is a two-line header at the top of the file which is being sorted to the bottom of the file (as each header line begins with a colon).
Is there a way to tell sort either "pass the first two lines across unsorted" or to specify an ordering which sorts the colon lines to the top - the remaining lines are always start with a 6-digit numeric (which is actually the key I'm sorting on) if that helps.
Example:
:0:12345
:1:6:2:3:8:4:2
010005TSTDOG_FOOD01
500123TSTMY_RADAR00
222334NOTALINEOUT01
477821USASHUTTLES21
325611LVEANOTHERS00
should sort to:
:0:12345
:1:6:2:3:8:4:2
010005TSTDOG_FOOD01
222334NOTALINEOUT01
325611LVEANOTHERS00
477821USASHUTTLES21
500123TSTMY_RADAR00
If you don't mind using
awk
, you can take advantage ofawk
's built-in pipe abilitieseg.
This prints the first two lines verbatim and pipes the rest through
sort
.Note that this has the very specific advantage of being able to selectively sort parts of a piped input. all the other methods suggested will only sort plain files which can be read multiple times. This works on anything.
You can use
tail -n +3 <file> | sort ...
(tail will output the file contents from the 3rd line).Here's a bash shell function derived from the other answers. It handles both files and pipes. First argument is the file name or '-' for stdin. Remaining arguments are passed to sort. A couple examples:
The shell function:
So here's a bash function where arguments are exactly like sort. Supporting files and pipes.
How it works. This line checks if there is at least one argument and if the last argument is a file.
This saves the file to separate argument. Since we're about to erase the last argument.
Here we remove the last argument. Since we don't want to pass it as a sort argument.
Finally, we do the awk part, passing the arguments (minus the last argument if it was the file) to sort in awk. This was orignally suggested by Dave, and modified to take sort arguments. We rely on the fact that
$file
will be empty if we're piping, thus ignored.Example usage with a comma separated file.
This will do what you want.
In simple cases,
sed
can do the job elegantly:or equivalently,
The key is in the
1q
-- print first line (header) and quit (leaving the rest of the input tosort
).For the example given,
2q
will do the trick.The
-u
switch (unbuffered) is required for thosesed
s (notably, GNU's) that would otherwise read the input in chunks, thereby consuming data that you want to go throughsort
instead.