Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

I want to store all possible dates between two user input dates. The input will be as like 20140605 and 20140830.

I want to store every date between the given dates into a variable using a loop so that I can use it.

The date generated or calculated must be in the same format as the input.

startdate=20141030
starttime=165800

enddate=20141120
endtime=175050

day=`expr $startdate % 100`
month=`expr $startdate % 10000`
year=`expr $startdate % 100000000`
month=`expr $month / 100`
year=`expr $year / 10000`
echo "$year  $month  $day"

while [ $enddate -ge $cdate ]
do
var=$cdate

#using variable var

if  [ $day -eq 31 ]; then
cdate=`expr $cdate - $day`
day=1
((month++))
cdate=`expr $cdate + 100 + $day`
#cdate=`expr $cdate + $day`
    if  [ $month -eq 13 ]; then
        #tmp=`expr $month \* 100`
        cdate=`expr $cdate - $month \* 100`
        month=1
        ((year++))
        cdate=`expr $cdate + 10100`
        if [ $year -eq 2999 ]; then
            ((year++))
            echo $cdate
            cdate=30010100
        fi
    fi
else
    ((day++))
    ((cdate++)) 
fi

if [ $enddate == $cdate ]; then
check=1
fi
done

I have tried to implement my requirement this way. But on compilation it says:

unary operator expected

What is the cause of this error, and how can I do this in a better way using a shell script?

share|improve this question
    
What shell do you use, Bash? Does the error give a line number? –  drs Jul 7 at 12:00
    
When you say all dates, can we assume you mean all days? All hours? All minutes? What do you mean "on compilation"? Are you somehow compiling your shell script into a binary? Why do you need to store these in a variable? It would be simpler to check whether a given date falls inside your range. –  terdon Jul 7 at 12:06
    
@drs Yes I am using bash. The while loop condition statement gives an error and other unkniwn line gives expr: syntax error –  FredOscatore Jul 7 at 12:21
    
@terdon Yes you can assume all minutes and seconds. No I am not compiling it into binary. I need to store the date into a variable because I want to use that variable into find command to find the files having those dates on their filename. –  FredOscatore Jul 7 at 12:24
1  
Every second? That can be huge and it is a horribly complex way of doing it; why not specify a date range and give that to find directly? I don't even understand how you could possible pass your shell variable to find short of running a separate find call for each of the millions of seconds between your dates. –  terdon Jul 7 at 12:40
show 6 more comments

2 Answers 2

up vote 4 down vote accepted

I would take a completely different approach to this. Doing all the date calculations by hand is error prone (there aren't always 31 days in a month, you have leap years, etc). Plus skimming through your code, it's very hard to tell what you're doing (which is a very bad thing).

#!/bin/bash
startdate=20141030
enddate=20141120

dates=()
for (( date="$startdate"; date != enddate; )); do
    dates+=( "$date" )
    date="$(date --date="$date + 1 days" +'%Y%m%d')"
done
echo "${dates[@]}"

This uses the date command to handle all computations, storing each date in the $dates array.

The result looks like this:

20141030 20141031 20141101 20141102 20141103 20141104 20141105 20141106 20141107 20141108 20141109 20141110 20141111 20141112 20141113 20141114 20141115 20141116 20141117 20141118 20141119
share|improve this answer
    
This makes perfect sense but, unfortunately, the OP actually wants all seconds between the two dates. –  terdon Jul 7 at 13:13
    
@Patrick This is just what I needed. Works like a charm. Thanks! –  FredOscatore Jul 8 at 4:03
add comment

If, as you explained in your comments, your end goal here is to find all files modified within a given date range, then saving said range into a variable is pointless. Instead, you can give the range to find directly:

find . -mtime $start -mtime $end

Personally, I would use a different approach. Just create two temp files, one created a second before your start date and one created a second after your end date. Then use GNU find's -newer test to find files that are newer than the first and not newer than the latter.

The tricky bit is getting $start and $end correctly. You could try something like:

#!/usr/bin/env bash

## If you really want to use this format, 
## then you must be consistent and always 
## us YYYYMMDD and HHMMSS.
startdate=20141030
starttime=165800

enddate=20141120
endtime=175050

## Get the start and end times in a format that GNU date can understand
startdate="$startdate $( sed -r 's/(..)(..)(..)/\1:\2:\3/' <<<$starttime)"
enddate="$enddate $( sed -r 's/(..)(..)(..)/\1:\2:\3/' <<<$endtime)"

## GNU find has the -newer test which lets you find files
## that are newer than the target file. We can use this
## and create two temporary files with the right dates.
tmp_start=$(mktemp)
tmp_end=$(mktemp)

## Now we need a date that is one seond before the
## start date and one second after the end date.
## We can then use touch and date to set the creation date 
## of the temp files to these dates. 
minusone=$(date -d "$startdate -1 sec" +%s)
plusone=$(date -d "$enddate +1 sec" +%s)

## Set the creation times of the temp files.
## The @ is needed when using seconds since
## the epoch as a date string.
touch -d "@$minusone" $tmp_start
touch -d "@$plusone" $tmp_end

## At this point we have two files, tmp_start and
## tmp_end with a creation date of $startdate-1 
## and $enddate+1 respectively. We can now search
## for files that are newer than one and not newer
## than the other.
find . -newer $tmp_start -not -newer $tmp_end

## Remove the temp files
rm $tmp_start $tmp_end
share|improve this answer
    
You misunderstood me, The Date is in the Filename and is not the last modified or access date. Btw Thanks for your effort and help. :) –  FredOscatore Jul 8 at 4:04
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.