Similar to this: Move Movies of different Encodes to a common Folder with original Movie Title
I have a series of PSB and Png export files I wanted all moved to common directories. I don't care if its PowerShell or Bash. I tried both the solutions on that link above, but neither worked. Mine at least appears to be a simpler problem though that I can't find a solution to....
I have several files that I just have the following formatting:
Filename1.psb Filename2.psb filename3.psb Filename4final.gammaOMega.psb Example3.psb Example4.png
They might not all be in the same folder, nor all have common casing and may have random characters or spacing in the file names. The number Zero, a space, or special character might sometimes be used as well in place of a number. However, I can guarantee the first 4-7 chracters of the naming conventions are the same letters on all files. They are all in my Onedrive folder though, just might not be all in the same subfolder.
My goal is to consolidate all of the files to folders to common Folders as follows:
File | Folder |
---|---|
Filename1.psb | Filename |
Filename2.psb | Filename |
filename3.psb | Filename |
Filename4final.gammaOMega.psb | Filename |
Example3.psb | Example |
Example4.png | Example |
Because I occasionally slip up and use the same name of file that may be a different revision, rather than overwriting, I prefer to keep both copies instead and rename the later file with.1.psb, .2.psb, etc and so forth. The file can be overwritten if the name, size, and date modified are identical.
What would be the best solution for this in Windows 10? I wouldn't even care if there was a simply batch file solution even.
Would it also be possible to set up a flag to ignore certain directories within the OneDrive folder as well?
DISCLAIMER this answer is based on those statements
If you want to dynamically create those folder when two files got something in common on the name
Yup that's what I'm saying.
If you want to only extract the alphabetical part of the filenames before the first digit to make it a folder name, it's more simpler and you can go for this solution .
But if you want to dynamically generate folder on what two filenames have in common regardless of if this is alphabetical or numerical characters, you could try something like:
#!/bin/bash
# Change those variable according to your wanted path
# You can just export them before starting this script to override those default values
[[ -z $FOLDERS_PATH ]] && FOLDERS_PATH="."
[[ -z $FILES_PATH ]] && FILES_PATH="."
declare -a FOLDER_NAMES
# Convert a string into PascalCase
to_pascal_case() {
str="${1,,}"
echo "${str^}"
}
# Get a list of directory to create based on what file's names got in common
directories_to_create() {
find "${FILES_PATH}" -type f|sed -e 'N;s/^\(.*\).*\n\1.*$/\1/'|awk -F '/' '
BEGIN {
previous_file="to_ignore"
}
($NF ~ ".+") {
file=tolower($NF);
files[file]=file
}
END {
asorti(files, sorted_files);
for (i in sorted_files) {
file=sorted_files[i];
if(!(file ~ previous_file".*")) {
print file
}
previous_file=file
}
}'
}
# Create the directory dynamically and build an array of those directories
create_directories() {
while read -r folder_name; do
formatted_folder_name="$(to_pascal_case "${folder_name}")"
mkdir -p "${FOLDERS_PATH}/${formatted_folder_name}"
FOLDER_NAMES+=("${formatted_folder_name}")
done < <(directories_to_create)
}
# Move if the filename match the directory name
move_if_it_match() {
file_name="${1}"
folder_name="${2}"
complete_file_path="${3}"
[[ ${file_name,,} =~ ^"${folder_name,,}".* ]] && mv "${complete_file_path}" "${FOLDERS_PATH}/${folder_name}"
}
# Moving the files if their name match with the folders (case insensitive match)
move_files() {
find "${FILES_PATH}" -type f|while read -r file_path; do
file_name="$(basename "$file_path")"
for folder_name in "${FOLDER_NAMES[@]}"; do
move_if_it_match "${file_name}" "${folder_name}" "${file_path}"
done
done
}
# Main program
create_directories
move_files
Demo:
$ find . -type f
./Example3.psb
./Example4.png
./Example5.png
./move.sh
./filename3.psb
./Filename1.psb
./Filename2.psb
./Filename4final.gammaOMega.psb
./Example with_spaces.mp4
$ bash move.sh
$ find . -type f
./move.sh
./Example/Example3.psb
./Example/Example4.png
./Example/Example5.png
./Example/Example with_spaces.mp4
./Filename/filename3.psb
./Filename/Filename1.psb
./Filename/Filename2.psb
./Filename/Filename4final.gammaOMega.psb
Would you please try the following:
#!/bin/bash
while IFS= read -r -d "" f; do
base=${f##*/}; base=${base//[^a-zA-Z]*} # extract "basename"
dir=${base,,}; dir=${dir^} # convert to Camelcase
mkdir -p -- "$dir" # create the directory
mv -- "$f" "$dir" # move to the directory
done < <(find . -type f \( -iname "*.psb" -o -iname "*.png" \) -print0)
find..
statement finds the specified files recursively and feed the filenames to the while
loop delimited with the null character (to allow whitespaces and other special characters in the filename). -d ""
option tells read
to split the input on the null characters. ${f##*/}
removes directory path. ${base//[^a-zA-Z]*}
removes non-alphabetical character and the following characters. ${base,,}
converts the characters to lowercase. ${dir^}
converts the first character to uppercase.
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.