segfaulter09
segfaulter09

Reputation: 45

BASH scripting sorting by date

I'm new to scripting in bash and our professor had us sort a file in this format

peas|10.00|05 Apr 2012
pea soup|10.00|05 Jan 2012
ham|10.00|06 Apr 2012

using the date on the third field, with the most recent item appearing on top. I've tried using combinations of filters and sort but they didn't work. Can anyone help me? thanks

Upvotes: 3

Views: 6437

Answers (4)

potong
potong

Reputation: 58420

This may work for you (GNU sort):

 sort -t'|' -k3.8,3.11nr -k3.4,3.6Mr -k3.1,3.2nr file

Or (if you don't have GNU sort):

sed '1{x;s/^/Jan01Feb02Mar03Apr04May05Jun06Jul07Aug08Sep09Oct10Nov11Dec12/;x};G;s/\(.*|\(..\) \(...\) \(....\)\)\n.*\3\(..\).*/\4\5\2 \1/' file
sort -nr |
sed 's/^[^ ]* //'

Upvotes: 1

sorpigal
sorpigal

Reputation: 26086

Similar to kev's answer, here's one that doesn't use awk

while IFS=\| read -r item price date ; do printf '%s|%s|%s|%s\n' "$(date +%s -d "$date")" "$item" "$price" "$date" ; done < table.txt | sort -n -t\| | cut -d\| -f2-

The idea is to add a field sort can use, sort by it, then strip it.

Upvotes: 0

pizza
pizza

Reputation: 7630

try

sort  -t '|' -k 3.8,3.11nr  -k 3.4,3.6Mr -k 3.1,3.2nr < input
      ------ -------------  ------------ ------------
      sep    first key      second key   third key

Upvotes: 16

kev
kev

Reputation: 161674

$ cat input.txt | awk -F '|' '{sprintf("date +%%s -d \"%s\"", $3) | getline tm}; {print tm "\t" $0}' | sort | cut -f2-
pea soup|10.00|05 Jan 2012
peas|10.00|05 Apr 2012
ham|10.00|06 Apr 2012

If you don't want call external command date,
you can write a custom mktime2 function in awk:

#!/bin/gawk -f
# script.awk

BEGIN {
    FS="|"
    m["Jan"] = "01"
    m["Feb"] = "02"
    m["Mar"] = "03"
    m["Apr"] = "04"
    m["May"] = "05"
    m["Jun"] = "06"
    m["Jul"] = "07"
    m["Aug"] = "08"
    m["Sep"] = "09"
    m["Oct"] = "10"
    m["Nov"] = "11"
    m["Dec"] = "12"
}

{
    print mktime2($3) "\t" $0 | "sort | cut -f2-"
}

function mktime2(s,    arr,yyyy,mm,dd)
{
    split(s, arr, " ")
    yyyy = arr[3]
    mm = m[arr[2]]
    dd = arr[1]
    return mktime(sprintf("%s %s %s 00 00 00", yyyy, mm, dd))
}

# make script executable
$ chmod +x script.awk

# run the script
$ ./script.awk input.txt
pea soup|10.00|05 Jan 2012
peas|10.00|05 Apr 2012
ham|10.00|06 Apr 2012

Upvotes: 3

Related Questions