I have files in the format YYYY_MM_DD_HH:MM:SS.swf that dump into a folder /home/user/dump/

I want to move these files into a new directory tree /home/user/save/year/month/day/ based on the YYYY_MM_DD from the filename. Alternatively, if these can be modified by the file modification date, that is acceptable as well. I've found a couple other scripts on here, but they don't seem to have all the info I'm looking for.

  • what did you do so far ? What is failing ? – MelBurslan Feb 29 '16 at 21:33
  • I've tried this script on the first response, but it spits out an error on line 21. I'm not sure if it would output the /year/month/day/ structure. – RickA Feb 29 '16 at 21:38
  • All files hold this same pattern. No, no directories should be ignored. Hopefully the format is something like 2016/02/29 – RickA Feb 29 '16 at 23:15
while read file
     f=$(basename $file)
     year=$(echo "$f"|cut -f1 -d_)
     day=$(echo "$f"|cut -f3 -d_)
     month=$(echo "$f"|cut -f2 -d_)
     mkdir -p "$new_dir"
     mv "$file" "$new_dir"
done < <(find /home/user/dump -type f -name "*_*_*_*:*:*.swf")
  • I ran this script, and it created /home/user/dump/home/user/save/2016/02/file.swf -- it is missing the day folder. I might be missing something here but this is close – RickA Feb 29 '16 at 23:21
  • Perhaps you're wrong about the file format? Because this should just work. – Gregg Leventhal Feb 29 '16 at 23:25
  • Show me the output of ls where the files live perhaps? – Gregg Leventhal Feb 29 '16 at 23:26
  • This is actually very close. 'for file in $(find /home/user/dump/ -name "*.swf") do year=$(echo ${file}|cut -d_ -f1) month=$(echo ${file}|cut -d_ -f2) day=$(echo ${file}|cut -d_ -f3) if [ ! -d /home/user/dump_save/${year}/${month}/${day} ] then mkdir -p /home/user/dump_save/${year}/${month}/${day} fi mv ${file} /home/user/dump_save/${year}/${month}/${day} done ' This duplicates the directory, though and creates 'user/dump_save/home/user/dump/2016/02/day' where the day is working correctly. ls of where the files lives /home/user/dump/2016_02_26_06:51:40.swf – RickA Feb 29 '16 at 23:33
  • It shouldn't, that isn't what the code says to do, are you editing the code? How are you running it? Both answers given to you were correct as far as I can see, so my instinct is that you are leaving out info, or doing something incorrectly. – Gregg Leventhal Feb 29 '16 at 23:35

If you have the Perl-based rename (sometimes known as prename) you can do this with a single command:

cd /home/user/dump
rename -v 'use File::Path qw(make_path); m!^((....)_(..)_(..)_(.*))!; my $d = "$2/$3/$4"; make_path($d); s!^!$d/!' *

Actually this is a fairly ugly (mis)use of rename. For each file, the code runs as follows

  1. Include a system library that allows for directory path creation
  2. Match against the YYYY_MM_DD structure at the beginning of the filename
  3. Create the corresponding directory path YYYY/MM/DD (if necessary)
  4. Move (rename) the file into its YYYY/MM/DD directory, leaving its name unchanged


Use the zmv function to move or rename files matched by a wildcard expression. There's no built-in way to create the destination directory, so I provide a function to do it.

autoload -U zmv
mkdir_mv () {
  mkdir -p -- ${(P)#:h}
  mv -- $@
cd /home/user/dump
zmv -p mkdir_mv '(????)_(??)_(??)_??:??:??.swf' '/home/user/save/$1/$2/$3/$f'

POSIX shell

If you need a portable solution, use a shell loop over the files, and shell string manipulation to extract the parts of the file names.

cd /home/user/dump
for f in ????_??_??_??:??:??.swf; do
  year=${f%%_*}; suffix=${f#*_}
  month=${suffix%%_*}; suffix=${suffix#*_}
  mkdir -p "/home/user/save/$year/$month/$day"
  mv "$f" "/home/user/save/$year/$month/$day/$f"
for file in $(find /home/user/dump/ -name "*.swf")
  year=$(echo ${file}|cut -d_ -f1)
  month=$(echo ${file}|cut -d_ -f2)
  day=$(echo ${file}|cut -d_ -f3)
  if [ ! -d /home/user/save/${year}/${month}/${day} ]
    mkdir -p /home/user/save/${year}/${month}/${day}
  mv ${file} /home/user/save/${year}/${month}/${day}
  • This is close - it moves the files, but 'doubles' the directory tree, i.e. saves the files in /home/user/save/home/user/save/year/month. Also, it omits the 'Day' folder – RickA Feb 29 '16 at 23:06
  • Then your file name format is not what you presented it to be, i.e. YYYY_MM_DD_HH:MM:SS.swf. Please post a section of the output from `ls -l /home/user/dump/" – MelBurslan Feb 29 '16 at 23:18
  • File format example '"/home/user/dump/2016_02_26_06:51:40.swf"' or '2016_02_27_09:57:14.swf' – RickA Feb 29 '16 at 23:27
  • Note that this would choke on file names containing spaces and other special characters. Also using pipes to cut to process strings is rather slow. – Gilles 'SO- stop being evil' Dec 26 '16 at 23:46

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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