-2

I have a folder with files such as:

20170129-aaa.jpg
20170130-bbb.jpg
20170131-ccc.jpg
20170201-ddd.jpg
20170202-eee.jpg

If a file is not in current month, I'd like to create folders based on the YYYYMM part of the files, and move it to its corresponding folder. (eg. 20170129-aaa.jpg -> 201701/20170129-aaa.jpg). But if a file is in current month, I'd like to leave it as is. I'm new to bash, my attempts on awk, uniq, substring are all failed. How can I make this work?

TessellatingHeckler
  • 27,511
  • 4
  • 48
  • 87
0PT1MU5 PR1ME
  • 45
  • 1
  • 11
  • Loop for each line {dir=$(cut -d '-' -f1 line); mkdir $dir;mv line $dir} – Karthick Vinod Feb 16 '17 at 04:52
  • Thank you for your answer. I just need the YYYYMM part, so cut by '-' doesn't quite apply here. – 0PT1MU5 PR1ME Feb 16 '17 at 05:03
  • Maybe I should write the first 6 digits of each line to a temp file, and use `uniq` to extract the YYYYMM? I'm just thinking this may make the script too bulky. Is there a lighter way? – 0PT1MU5 PR1ME Feb 16 '17 at 05:22
  • You're supposed to post the code you have, explain what problem you have with it, so other people can help you fix your code. Explaining "the bit that's going wrong" clearly can be enough work that you understand it much better, maybe fix it yourself, and it makes your question useful to other people - "how do I get the current year and month?" is something many people might want - the whole point of the site. Without code, it's "write a script for me" - more work, you learn less, less useful for others. "Free code writing" is something people don't want to encourage. Hence, downvotes. – TessellatingHeckler Feb 16 '17 at 07:39
  • I just don't want to make my question too lengthy. Before i finally made my own code work, i don't even know if that way is right or wrong. The answer to my question may have to cover uniq, sort, for, etc. I'm willing to show all my failed attempts, but like i said it'll be too long. I didn't want to waste others' time. Thank you for explaining, now i understand why downvoted. And i don't blame anyone anymore. It's just my thought doesn't follow so's spirit. My bad. – 0PT1MU5 PR1ME Feb 16 '17 at 08:01

3 Answers3

2

You could loop through your files like this in Bash:

shopt -s nullglob
today=$(date +%Y%m)
for file in ${today}??-???.jpg; do
  dir=${file:0:6}
  mkdir -p "$dir" || continue
  mv "$file" "$dir/$file"
done
  • date +%Y%M extracts the current date in the YYYYMM format
  • shopt -s nullglob makes sure glob expands to nothing in case of no matching files
  • the glob ${today}??-???.jpg makes sure that the loop picks up the matching files
  • dir=${file:0:6} extracts the YYYYMM portion from file name
  • mkdir -p creates the directory (ignores if dir already exists)
  • || continue will skip the file if the directory creation fails

Related posts:

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
codeforester
  • 39,467
  • 16
  • 112
  • 140
  • Thank you very much for your answer. My bad, I missed a requirement in my initial post. I'd like to only move the files not in current month to its directory. But those in current month should be left as is. – 0PT1MU5 PR1ME Feb 16 '17 at 05:12
  • A look at `man date` or a few searches on this site will help you build the logic yourself. It is a very simple change. – codeforester Feb 16 '17 at 05:49
  • I have searched different keywords on google for hours before I came here for help. Well, apparently it's my fault not finding the right keywords. – 0PT1MU5 PR1ME Feb 16 '17 at 06:13
  • Here is an useful post: http://stackoverflow.com/questions/1401482/yyyy-mm-dd-format-date-in-shell-script – codeforester Feb 16 '17 at 06:17
1

This script does what you want (based on reply from codeforester):

curmonth=$(date +%Y%m)
for filename in ????????-???.jpg; do
  filemonth=${filename:0:6}
  [ $curmonth = $filemonth ] && continue;
  [ ! -d $curmonth ] && mkdir $curmonth
  if [ ! -d $curmonth/. ]; then
    echo "$0: error: Can not create directory $curmonth"
    break
  fi
  mv $filename $curmonth
done
  1. A variable holds current year month.
  2. All the files with the "????????-??.jpg" pattern are examined.
  3. The month in the filename is extracted.
  4. If the month of the file equals the current one, skip
  5. If doesn't exist the destination directory, create it
  6. ENSURE the destination directory is there, otherwise mv turns destructive
  7. Finally move the file

There is a bug in this code: if it happens that a destination directory, like "201702", already exists but it is not writable, then the mv will fail. If the directory does not exist, then it is created, and it is assumed that a directory just created is writable (normally it is... are we 100% sure?) :-)

0
IDX=$(ls *.jpg -1 | xargs -n1 basename | cut -b 1-6 | uniq | wc -l)
for YYYYMM in $(ls $FILEDIR/*.jpg -1 | xargs -n1 basename | cut -b 1-6 | uniq | head -$(($IDX-1)));
do
    mkdir -p $FILEDIR/$YYYYMM
    mv "$FILEDIR/$YYYYMM"*.jpg $FILEDIR/$YYYYMM
done
0PT1MU5 PR1ME
  • 45
  • 1
  • 11