简体   繁体   中英

How do you move files of specific file extension in multiple directories, one directory deeper within their respective directories?

I'm hoping someone can help me, I'm looking for help with a bash script to move files by file extension from multiple directories, one directory deeper within their respective directories.

For example I have a 'Projects' directory, that has multiple directories within in it 'Project 001, Project 002, Project 003' and so on. I have '.JPG' files in those folders and want to put them in a 'JPG' folder within their respective project folder - how would I do this with a bash script as there are too many to do by hand?

To make matters more complicated some of those project folders already have 'JPG' folders in them, and some of those have some of the files already in them as duplicates, so I think I'd need to add an overwrite confirmation to it too based on filename.

I know a little bash, but this is a little over my head, so any help would be greatly appreciated.

Thanks,

/ Hami

This is using a CLI on Ubuntu Server 18.04 LTS, on a disk with thousands of directories with human filenames - spaces, parenthesis, and varied unicode character such as Japanese, and European. The names of the directories are varied, and have no particular formula.

Ideally, I'd like to go from this:

  • Projects
    • Project 001
      • Image 001.jpg
    • Project 002
      • Image 002.jpg
      • Image 003.jpg
    • Project 003

...to this:

  • Projects
    • Project 001
      • JPG
        • Image 001.jpg
    • Project 002
      • JPG
        • Image 002.jpg
        • Image 003.jpg
    • Project 003

You can do what you need with find that searchers for all *.jpg files and a simple helper script called by the -exec option to find to create the jpg directory and move all .jpg files into the new directory.

The helper script will simply get the absolute filename utilitzing readlink -f and then using quick parameter expansion to trim the last /... component from the absolute filename to obtain the full path. Then it is simply a matter of creating the jpg directory at the end of the path and moving the file to the new directory.

Your helper script (I called it helper.sh ) could be:

#!/bin/sh

test -z "$1" && exit                        ## validate 1 argument given or exit

full=$(readlink -f "$1")                    ## get full filename
dir="${full%/*}"                            ## get full path

test "${full##*.}" = 'jpg' || exit          ## test extension is jpg or exit

test -z "$dir" && dir="/"                   ## check if file was in / (root) 

test -d "$dir/jpg" || mkdir -p "$dir/jpg"   ## check/create jpg dir at end of path

mv "$full" "$dir/jpg"                       ## move file into new jpg dir

( note: after creating the helper script, make sure you make it executable with chmod +x helper.sh )

Original Projects Directory Tree

$ tree Projects/
Projects/
├── Project_001
│   └── Image_001.jpg
├── Project_002
│   ├── Image_002.jpg
│   └── Image_003.jpg
└── Project_003

Your find command operating on the Projects directory calling the helper script for each file would be:

$ find Projects/ -type f -name "*jpg" -exec ./helper.sh '{}' \;

Resulting Projects Directory Tree

$ tree Projects/
Projects/
├── Project_001
│   └── jpg
│       └── Image_001.jpg
├── Project_002
│   └── jpg
│       ├── Image_002.jpg
│       └── Image_003.jpg
└── Project_003

Let me know if you have further questions.

Preserving Files Already In jpg Directory

Per-your additional comment, in order to preserve .jpg files already within a jpg directory under your Projects, all you need to do is add one additional check. If the last component of the path is already jpg , just exit the helper, eg

test "${dir##*/}" = 'jpg' && exit           ## if already in jpg dir, exit

Shown in context in helper.sh :

test -z "$1" && exit                        ## validate 1 argument given or exit

full=$(readlink -f "$1")                    ## get full filename
dir="${full%/*}"                            ## get full path (trim last /*)

test "${dir##*/}" = 'jpg' && exit           ## if already in jpg dir, exit
test "${full##*.}" = 'jpg' || exit          ## test extension is jpg or exit
...

Original Projects Directory Tree (w/existing jpg)

$ tree Projects/
Projects/
├── Project_001
│   ├── Image_001.jpg
│   └── jpg
│       └── Image_000.jpg
├── Project_002
│   ├── Image_002.jpg
│   ├── Image_003.jpg
│   └── jpg
│       ├── Image_000.jpg
│       └── Image_001.jpg
└── Project_003

Resulting Projects Directory Tree

$ tree Projects/
Projects/
├── Project_001
│   └── jpg
│       ├── Image_000.jpg
│       └── Image_001.jpg
├── Project_002
│   └── jpg
│       ├── Image_000.jpg
│       ├── Image_001.jpg
│       ├── Image_002.jpg
│       └── Image_003.jpg
└── Project_003

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM