[Wylug-discuss] Copy files by date

Smylers Smylers at stripey.com
Fri Jan 27 10:55:54 UTC 2012


linux at sh2515.plus.com writes:

> > What about the variant I gave which used Perl to calculate the date?
> >
> > If you need to install a Perl module, note you can do that as a normal
> > user and put it under your home directory; you don't need to be root or
> > install it system-wide.
> 
> I am sure it will work, but I don't know perl to finish off the rest of
> the program.

You don't need to. The Perl one-liner I gave just outputs yesterday's
date, so you can embed it in $(...) and pass it to -newermt just as with
the date command.


> I am now thinking about doing something that will put them in certain
> folders to make it easier for people to get to.
> 
> today=$(date +%d-%m-%y)
> for FILE in $(find . -iname '*.txt' -newermt $(date +%F) do;

Note that that will be problematic if any of your *.txt files can have
spaces in their names; you would have to use something like find with
-print0 and xargs -0 if you want to allow for that.

> if ($FILE='*AA*.txt)

The parens there tell Bash to start a subshell, so (addding in the
closing quote mark which I'm presuming you meant) it will first try to
execute the command:

  $FILE='*AA*.txt'

The $ causes interpolation of the following named variable. Suppose that
the for loop has set FILE to laptops.txt, then the command run will be:

  laptops.txt='*AA*.txt'

That almost certainly isn't the name of a valid command in your path(!),
so will fail.

In if statements [[ ... ]] is what you often want for testing
conditions, and indeed pattern matching is one of its capabilities. See:

  $ help [[

So you could do something like:

  if [[ "$FILE" == *AA*.txt ]]

Though note that that pattern will match things like these, which you
might've meant to categorize under ZZ rather than AA:

  ZZ_AARDVARK.txt
  AAAARGH/ZZ.txt

> then
> mkdir ~/test/AA/$today

If ~/test/AA/ doesn't already exist, then that will fail and the
subdirectory with today's date won't be created, so you'd need to create
~/test/AA/ and so on in advance.

Less seriously, if the subdirectory ~/test/AA/$today/ already exists
(because this is the second AA file you've encountered today and it was
created when you found the first one) then the mkdir will also fail and
give an error message.

Using mkdir -p solves both those problems, creating any directories that
are needed (perhaps none).

(Also if you're naming directories after dates I'd really recommend you
use the %F (yyyy-mm-dd) format rather than putting the day first. It's
much easier to deal with them and find things when they are sorted in
date order.)

> cp $FILE ~/test/AA/$today

If your find command finds both of these files:

  ./aieee/AA_zamm.txt
  ./clunk/AA_zamm.txt

then both will be copied directly into ~/test/AA/$today, with the second
overwriting the first.

If you want to allow for having the same-named file in different
subdirectories then you need to replicate the entire directory tree, not
just the filename.

Also I'd recommend using cp -p, to copy across the ownership and timestamps
on the files, otherwise they'll get timestamps of the time you make the
copies.

> else
> if ($FILE=*BA*.txt)
> then
> mkdir ~/test/BA/$today
> cp $FILE ~/test/BA/$today
> .....
> more of the same

That's going to get very tedious if you have to copy and paste it 26 *
26 times.

If what you actually want is to get the first two letters of the
filename then I'd try something along these lines:

  basename="${FILE##*/}"
  subdir=~/test/"${basename:0:2}/$today"
  mkdir -p $dir
  cp -p "$FILE" $dir

The ## removes everything up to the final / in the full filename, to set
just the basename. Then the :0:2 gets just the first two characters of
that.

In bash(1) search for "##" and ":length" for details.

> Also because there are a lot of files, would I be able to put xargs in
> instead of cp, I am thinking no because it is a batch process rather
> than running on each instance of $FILE through an if else if
> statement?

If you want to copy each file to a different subdirectory then yes each
file is going to need its own cp command; having xargs group them all
together into a single cp will only allow for a single destination
directory.

You can use xargs -n 1, to force xargs to issue a separate command for
each file. Obviously that doesn't give any performance advantage of
reducing the number of cp commands run, but if you'd prefer to use xargs
for some other reason (perhaps to be able to use -0) then it's possible.

However ... I still think that for what you're doing you'd be much
better off using rsync than trying to devise your own copying routine.

Cheers

Smylers



More information about the Wylug-discuss mailing list