0

Info

I have a string that has time info in it. I need to get only the number of months from this string. I'm trying to accomplish this using sed, but I haven't had too much luck yet. Using bash + command line tools is a requirement for me.

Current attempt

echo "1969 years 12 months 25 days 19 hours 38 minutes 24 seconds since last release" | sed -r "s/^([0-9]+).*/\1/"

returns 1969

Bonus

More generally, my problem is the entire "1969 years 12 months" portion of the string. I'm using date to get a time differential but I have to account for the 1970 start date. I find it odd that my current output expresses 1970 as 1969 year and 12 months.

Edit: I'm attempting to use nunk's solution from this post:

How to find the difference in days between two dates?

It works fine for everything, except for the months. The quantity of months is off by (12-printed number of months).

Community
  • 1
  • 1
Jefftopia
  • 2,105
  • 1
  • 26
  • 45
  • 2
    Why don't you use `grep -Po '(?<=years )\d*(?= months)'`? This will print digits in between "years" and "months". – fedorqui Sep 09 '14 at 15:37
  • 2
    We can't solve the bonus question if you don't give us the original inputs and tell us what you are doing to process them. – Etan Reisner Sep 09 '14 at 15:38
  • @EtanReisner, I updated my post with more details on the bigger-picture problem. – Jefftopia Sep 09 '14 at 15:44
  • What dates are getting you that output? – Etan Reisner Sep 09 '14 at 16:04
  • example input: `2014-09-03T14:44:48+00:00` and the current date. – Jefftopia Sep 09 '14 at 16:26
  • The solution you selected requires GNU sed so just use GNU awk instead with it's built in time functions and you can solve this plus whatever other problems you have all with one simple tool. Alsom, can't you fix whatever tool is generating "1969 years 12 months" instead of "1970 years"? If it's broken like that it may be broken in other ways too. – Ed Morton Sep 09 '14 at 16:26

4 Answers4

2

Does this suit:

echo "1969 years 12 months 25 days 19 hours 38 minutes 24 seconds since last release" | sed -r 's/.* ([0-9]+) months.*/\1/'

gives

12

What's happening here is this:

  • The "match" part of the expression will succeed if there are, in order, all of:
    • .* any stuff
    • a space
    • [0-9]+ one or more digit ("captured" using ( and ))
    • another space
    • months the word "months"
    • .* any stuff
  • If it succeeds, it's guaranteed to match the whole of the line, because of the .* at both ends.
  • Also, if it succeeds, the match (the whole line) is replaced by \1 which is a special code meaning "the contents of the first set of capture brackets. You'll see that the value captured by the brackets above is the number preceding the word "months".
Tim
  • 9,171
  • 33
  • 51
2

I would do this as next:

str="1969 years 12 months 25 days 19 hours 38 minutes 24 seconds since last release"

read y m d H M S < <(echo $(grep -oP '\d+' <<<"$str"))
echo "month: $m"
echo "year: $y"
#etc for $d $H $M $S

prints:

month: 12
year: 1969
  • the grep filter out all numbers (each to alone line)
  • the echo make from the numbers an space separated string
  • what will read the read and it will assign each number to the corresponsing variable
clt60
  • 62,119
  • 17
  • 107
  • 194
0

It sounds like you're trying to fix the output from running a buggy tool to diff dates. Just use GNU awk instead:

$ echo "2014-09-03T14:44:48+00:00" |
gawk '{gsub(/[-T:+]/," "); print (systime() - mktime($0)) / (24*60*60)}'
5.86991

Do whatever rounding you like on the number of days output, e.g.:

$ echo "2014-09-03T14:44:48+00:00" |
gawk '{gsub(/[-T:+]/," "); printf "%.0f\n", (systime() - mktime($0)) / (24*60*60)}'
6

Note that the implementation of rounding using "%.0f" is system dependent - it might round 0.5 up or it might round it towards the nearest even number. If that's a concern check your system and write your own rounding function if necessary.

Ed Morton
  • 188,023
  • 17
  • 78
  • 185
0

You could use Perl to separate out the key, value pairs:

$ str="1969 years 12 months 25 days 19 hours 38 minutes 24 seconds since last release"
$ echo $str | perl -lane 'print "$1 $2"  while /(\d+)\s(\w+)/g'
1969 years
12 months
25 days
19 hours
38 minutes
24 seconds

Then use grep to grab the one you want:

$ echo $str | perl -lane 'print "$1 $2"  while /(\d+)\s(\w+)/g' | grep 'months'
12 months
dawg
  • 98,345
  • 23
  • 131
  • 206