J Balrog
J Balrog

Reputation: 53

Select directories with date in their names from a date range

I'm creating a list of directories with the requested date range in their name.

Directories are all labeled other_2019-07-18T00-00-00. The T is messing me up!

Copied this loop from somewhere.

#!/bin/bash
curdate=$(date +%Y-%m-%d%H-%M-%S)
#
for o in other_*; do
    tmp=${o##other_}
      tmp=$(echo "$tmp" | sed 's/T//') # clean up prefixes
      fdate=$(date -d "${tmp}")
      (( curdate < fdate )) && echo "$o"
done

I expect the final echo to include the path of all dir that match.

Upvotes: 1

Views: 139

Answers (3)

F. Hauri  - Give Up GitHub
F. Hauri - Give Up GitHub

Reputation: 70732

Instead of dropping T...

date -d 2019-03-23T00-06-28
date: invalid date '2019-03-23T00-06-28'

ok, but:

date -d 2019-03-23T00:06:28
Sat Mar 23 00:06:28 UTC 2019

So we have to replace last two dashes by ::

As your question is tagged bash:

file="somepath/other_2019-07-18T00-00-00.extension"
time=${file#*other_}    # suppress from left until 'other_'
time=${time%.*}         # suppress extension
time=${time//-/:}       # replace all dash by a `:`
time=${time/:/-}        # replace 1nd `:` by a dash
time=${time/:/-}        # replace 1nd `:` by a dash (again)
date -d $time
Thu Jul 18 00:00:00 UTC 2019

This could by written:

printf -v now "%(%s)T" -1         # bashism for current date to variable $now
for file in somepath/other_*.ext ;do
    time=${file#*other_} time=${time%.*} time=${time//-/:}
    time=${time/:/-} time=${time/:/-}
    read fdate < <(date +%s -d $time)
    ((fdate > now)) && { echo $file: $((fdate - now)) ; }
done        

Reducing forks (to date) improve quickness:

for matching your sample, you could replace for file in somepath/other_*.ext ;do by for file in other_*; do. This must work quite same.

fifo=/tmp/fifo-date-$$
mkfifo $fifo
exec 5> >(exec stdbuf -o0 date -f - +%s >$fifo 2>&1)
echo now 1>&5
exec 6< $fifo
read -t 1 -u 6 now
rm $fifo
for file in otherdates/*.ext ; do
    time=${file#*other_} time=${time%.*} time=${time//-/:}
    time=${time/:/-} time=${time/:/-}
    echo $time 1>&5 && read -t 1 -u 6 fdate
    ((fdate > now)) && { 
        echo $file: $((fdate - now))
    }
done
exec 6>&-
exec 5>&-

In this, I run date +%s in background, with -f argument, date will interpret each incoming line, then answer UNIX_TIME. So $now is first read from date process, by:

echo now >&5 &&        # now, the string
    read -u 6 now      # read will populate `$now` variable

Nota, once fifo opened by both input and output, they could be deleted. It will remain for process until process close them.

Upvotes: 1

tshiono
tshiono

Reputation: 22012

Unlike AWK, Bash comparison operator < works only on numerical values.
Please try instead:

#!/bin/bash
curdate=$(date +%Y%m%d%H%M%S)

for o in other_*; do
    tmp=${o##other_}
    fdate=$(echo "$tmp" | sed 's/[-T]//g')  # numeralization
    (( curdate < fdate )) && echo "$o"
done

As an alternative, you can compare epoch times:

#!/bin/bash

curdate=$(date +%s)

for o in other_*; do
    tmp=${o##other_}
    tmp=$(echo "$tmp" | sed 's/T/ /' | sed 's/\([0-9][0-9]\)-\([0-9][0-9]\)-\([0-9][0-9]\)$/\1:\2:\3/')
    fdate=$(date -d "$tmp" +%s)
    (( curdate < fdate )) && echo "$o"
done

Hope this helps.

Upvotes: 1

J&#252;rgen H&#246;tzel
J&#252;rgen H&#246;tzel

Reputation: 19717

there is no space between day and hour, which causes date not to be able to read the date. Try:

sed 's/T/ /'

Upvotes: 0

Related Questions