1

I am trying to copy files using robocopy. The files I want to copy should be of last month(not one month old) i.e. on if I am running the script in the march month(any day) then it should copy all the files with timestamp of february. I am using below script:

robocopy source/*.prev destination maxage:20180201 minage:20180228

How to use the date as a variable here so I don't have to manually change it every month?

Yogi
  • 11
  • 3
  • 1
    Welcome to StackOverflow! The question you've asked is hard to answer using tools within Bash alone. Can you clarify what operating system you're running, so that if a solution requires additional tools, we can be more specific with the options they'll use? Also, have you tried reviewing the man pages for [`date`](https://man.freebsd.org/date) and [`find`](https://man.freebsd.org/find)? Might also want to consider [`rsync`](https://www.samba.org/ftp/rsync/rsync.html)? – ghoti Mar 31 '18 at 18:42
  • Also, can you tell us what "robocopy" you're using? The tag you've included is for a Windows utility. – ghoti Mar 31 '18 at 21:08
  • I am making a batch script to copy files with 2different extensions from one windows server to other. Thanks – Yogi Apr 01 '18 at 19:08
  • So .. if you need a Windows solution, why is your question tagged `bash`, and `unix`? – ghoti Apr 01 '18 at 19:32
  • @ghoti really sorry about that, it mistakenly selected in place of script.,, – Yogi Apr 01 '18 at 19:49
  • @ghoti and thanks you so much for help – Yogi Apr 01 '18 at 19:49
  • If you enter `RoboCopy /?` at the Command prompt, you'll note that its syntax, `RoboCopy [[ ...]] []`, seems contradictory to yours, `RoboCopy ` – Compo Apr 01 '18 at 21:57

4 Answers4

0

The last date you can calculate like this: date -d "-$(date +%d) days -0 month" +%Y-%m-%d

which today outputs: 2018-02-28

The first date is a simple fixed start day: date -d "-$(date +%d) days -0 month" +%Y-%m-01

Which gaves when executed today: 2018-02-01

Your command could thus be:

robocopy source/*.prev destination \
maxage:$(date -d "-$(date +%d) days -0 month" +%Y%m01) \
minage:$(date -d "-$(date +%d) days -0 month" +%Y%m%d)

Edit: Since this is using GNU date syntax, this might not work on unix as stated by @ghoti

Jonathan
  • 748
  • 3
  • 20
  • 2
    That usage of the `date` command is specific to GNU date; other versions of the command work differently (BSD, macOS, SysV, etc). Since the OP specified "unix", it seems reasonable to me that a portable answer would make sense. Can you add options, or at least qualify your answer as being platform-specific? – ghoti Mar 31 '18 at 18:38
0

Having GNU date around you can do it this way:

start=$(date -d "$(date +%Y-%m-1) -1 month" +%Y%m%d)
end=(date -d "$(date +%Y-%m-1) -1 day" +%Y%m%d)
robocopy source/*.prev destination maxage:${start} minage:${end}

See linux - Using date command to get previous, current and next month to see why we need -d. On 31st of a month the -1 month breaks otherwise.

Heiner Westphal
  • 348
  • 2
  • 4
  • 1
    This answer also is not a bash answer. It depends on `date`, which is *not* part of bash, and whose usage varies depending on operating system. The question specifies **unix**, not **Linux**. Please either provide something portable, or qualify your answer as being platform specific. – ghoti Mar 31 '18 at 18:44
  • Thanks ghoti, you are right. It's GNU date-, not linux-specific. I edited the answer accordingly. – Heiner Westphal Mar 31 '18 at 18:49
0

Let me assume POSIX compliant date is available.
Then how about:

#!/bin/bash

days[1]=31; days[2]=28; days[3]=31; days[4]=30
days[5]=31; days[6]=30; days[7]=31; days[8]=31
days[9]=30; days[10]=31; days[11]=30; days[12]=31

# current year and month
year=$(date +%Y)
month=$(( $(date +%m) + 0 ))

# previous month
if [[ "$month" = "1" ]]; then
    year=$(( $year - 1 ))
    month="12"
else
    month=$(( $month - 1 ))
fi
days=${days[$month]}

# a leap year correction
if [[ "$month" = "2" ]]; then
    days=$(( $days + ($year % 400 == 0 || ($year % 100 != 0 && $year % 4 == 0)) ))
fi

maxage=$( printf "%04d%02d%02d" $year $month 1 )
minage=$( printf "%04d%02d%02d" $year $month $days )
tshiono
  • 21,248
  • 2
  • 14
  • 22
0
@echo off
    setlocal enableextensions disabledelayedexpansion

    rem Initialize variables to hold the previous month information
    set "yyyy=" 
    set "mm="
    set "dd="

    rem The robocopy in the for command will generate an error with the current date
    for /f "tokens=1,2 delims=/" %%a in ('
        robocopy "|" . /njh
    ') do if not defined yyyy (
        rem Calculate previous month from current date
        set /a "mm=(1%%b-90) %% 12 + 1", "yyyy=%%a - !(mm %% 12)" 
        rem Calculate the last day of the previous month
        set /a "dd=30+((mm+mm/8) %% 2)+(-2+!(yyyy%%4)-!(yyyy%%100)+!(yyyy%%400))*!(%%b-3)" 
        rem Increase month and day for proper padding
        set /a "dd+=100", "mm+=100"
    )

    rem Leave only the two right digits in month and day
    set "mm=%mm:~-2%"
    set "dd=%dd:~-2%"

    rem Do the copy operation, selecting files from first to last days in previous month
    robocopy "x:\source" "y:\target" *.prev /maxage:%yyyy%%mm%01 /minage:%yyyy%%mm%%dd%
MC ND
  • 69,615
  • 8
  • 84
  • 126