0

I have hundreds of thousands of folders of photos. For whatever reason on the export they created several scenarios like this:

2019/01/01
2019/01/01 #2

How do I write a linux command (ideally which can be run on Mac) which can automatically move the files

from 
2019/01/01 #2 
to 
2019/01/01

Any help would be appreciated. This would need to work for any date and also merge the contents. Where I am struggling is I can't understand how to get the dir as the original format without the #

for dir in *#2/*; do mv "$dir"/* "${dir}"; done
Jimmy
  • 239
  • 3
  • 7
  • 21
  • SO is not a code writing service. You at least need to make and effort to write your own code. You can request help with specific problems during the process. – jordanm Feb 05 '20 at 21:08

2 Answers2

1

Backup your files before you try this. It could be destructive...

Part of the problem is using for when iterating through folders with some spaces in their names. You'll end up with an inconsistent list because whitespace and carriage returns are both field separators. You need to set IFS to a carriage return only. (You can use find -exec to work on filesystem entries directly, but that gets messy when working with nested wildcards)

This should do the job, but be warned that moved files will overwrite matching ones in the destination folders. Run it from the root folder of the above.

# Set IFS to carriage return only.
IFS='
'
# Find all the matching folders and move the .jpg files out of them to the sibling folder.
for a in $(find . -type d -name *#*); do b=${a::-3}; mv $a/*.jpg $b/; rmdir $a; done

A few assumptions made: - that the structure you've described is year/month/day subfolders. (If the folder names contain \ it gets uglier) - that you you just have some folders with a #2 suffix - that you want to remove the #2 folders once you've moved the files out.

See here for how to do more weird things with strings in bash...

SmallClanger
  • 8,947
  • 1
  • 31
  • 45
1

Using find and -exec:

find . -type d -name "* #*" -exec bash -O nullglob -c '
  for dir; do
    otherdir=${dir/ #*}
    if [ -d "$otherdir" ]; then
      for file in "$dir"/*; do
        mv -vi "$file" "$otherdir"
      done
      rmdir "$dir" && echo "deleted directory $dir"
    else
      mv -v "$dir" "$otherdir"
    fi
  done
' bash {} +

This will move all files from e.g. 2019/01/01 #2 to 2019/01/01 if the latter directory exists (if it doesn't exist, the folder with the # is renamed). If there are files in 2019/01/01 #2 that already exists in the other folder, it asks for permission to move the files.
When the move operation is done it tries to delete the (now empty) folder. All move/delete operations are in verbose mode.

The enabled nullglob in combination with the for-loop makes sure that "$dir"/* does not return any files if the directory is already empty.

Freddy
  • 1,999
  • 5
  • 12
  • Thank you for this. Just to check do I just paste this in terminal or do I need to run as part of a script – Jimmy Feb 09 '20 at 14:54
  • You can paste it as is in the terminal, but you can also include it into a script. `cd` into the parent directory of the `2019` folder first (or change the start directory `.` to an absolute path). I'm quite confident that the script works as expected, but please make a backup _before_ running this -- to be (a) to be on the safe side and (b) to be able to compare the old directory structure with the new one. – Freddy Feb 09 '20 at 15:08