Reputation: 3782
I have a folder with a lot of files named by date like this:
(Some numbers)-date-(somenumbers).filet ype
Where 'date' is listed like:
20150730225001 For July 30, 2015 at 0 10:50 (and 1 second)
Is there a quick way to organize this with the Ubuntu terminal to give a structure like this:
Current folder/year/month/day/hour/ (all files fitting criteria to be placed here)
I have tried looking for a solution to this but most have just confused me since I'm pretty new to Unix scripting.
Upvotes: 0
Views: 83
Reputation: 84559
The solution presumes you are using bash as your shell on Ubuntu and that you have all of the files you wish to organize in the current working directory. While not a one liner, you can accomplish what you are attempting with a few lines using string indexes to separate the various components of the date into year
, month
, day
and hour
relatively easily. Then using mkdir -p
to check/create the needed relative path and mv
to move the file to the new destination. A couple of compound commands can be added to provide a few sanity checks to insure you have a 14-digit
date/time string, etc.
There are a number of ways to approach the separation (e.g. date -d
, etc.), but simple string indexes are probably the most efficient. Let me know if you have questions:
A semi-one-liner with continuations
for i in *; do dt=${i%-*}; dt=${dt#*-}; [ ${#dt} -eq 14 ] || continue; \
y=${dt:0:4}; mo=${dt:4:2}; d=${dt:6:2}; h=${dt:8:2}; \
mkdir -p "$y/$mo/$d/$h" && mv "$i" "$y/$mo/$d/$h" || \
printf "error: unable to create: '%s'\n" "$y/$mo/$d/$h"; done
formatted
#!/bin/bash
for i in *; do
dt=${i%-*} ## separate date string from filename
dt=${dt#*-}
[ ${#dt} -eq 14 ] || continue ## validate 14 chars
y=${dt:0:4} ## separate into year, mo, day, hour
mo=${dt:4:2} # (you can add checks for ranges)
d=${dt:6:2}
h=${dt:8:2}
## create new dir & move or throw error
mkdir -p "$y/$mo/$d/$h" && mv "$i" "$y/$mo/$d/$h" || \
printf "error: unable to create: '%s'\n" "$y/$mo/$d/$h"
done
Upvotes: 1
Reputation: 29096
So with these two files inside foo/
42-20150730225001-473826.filet
98-20141115180001-482157.filet
You can either use this Perl script:
#!/usr/bin/perl
for(@ARGV) {
if (/.*-(\d{4})(\d\d)(\d\d)(\d+)-.*[.]filet/) {
`mkdir -p $1/$2/$3/ && mv $_ $1/$2/$3/$4.filet`;
}
}
or this oneliner:
ls | xargs perl -e 'for(@ARGV){qx{mkdir -p $1/$2/$3/ && mv $_ $1/$2/$3/$4.filet} if /.*-(\d{4})(\d\d)(\d\d)(\d+)-.*[.]filet/}'
Upvotes: 2