Home > Net >  Automator/Apple Script: Move files with same prefix on a new folder. The folder name must be the fil
Automator/Apple Script: Move files with same prefix on a new folder. The folder name must be the fil

Time:03-02

I'm a photographer and I have multiple jpg files of clothings in one folder. The files name structure is:

TYPE_FABRIC_COLOR (Example: BU23W02CA_CNU_RED, BU23W02CA_CNU_BLUE, BU23W23MG_LINO_WHITE)

I have to move files of same TYPE (BU23W02CA) on one folder named as TYPE.

For example:

MAIN FOLDER>

BU23W02CA_CNU_RED.jpg, BU23W02CA_CNU_BLUE.jpg, BU23W23MG_LINO_WHITE.jpg

Became:

MAIN FOLDER>

BU23W02CA_CNU > BU23W02CA_CNU_RED.jpg, BU23W02CA_CNU_BLUE.jpg

BU23W23MG_LINO > BU23W23MG_LINO_WHITE.jpg

CodePudding user response:

Here are some scripts.

V1

#!/bin/bash

find . -maxdepth 1 -type f -name "*.jpg" -print0 | while IFS= read -r -d '' file
do
    # Extract the directory name
    dirname=$(echo "$file" | cut -d'_' -f1-2 | sed 's#\./\(.*\)#\1#')
    #DEBUG echo "$file --> $dirname"

    # Create it if not already existing
    if [[ ! -d "$dirname" ]]
    then
        mkdir "$dirname"
    fi

    # Move the file into it
    mv "$file" "$dirname"
done
  • it assumes all files that the find lists are of the format you described in your question, i.e. TYPE_FABRIC_COLOR.ext.
  • dirname is the extraction of the first two words delimited by _ in the file name.
  • since find lists the files with a ./ prefix, it is removed from the dirname as well (that is what the sed command does).
  • the find specifies the name of the files to consider as *.jpg. You can change this to something else, if you want to restrict which files are considered in the move.
  • this version loops through each file, creates a directory with it's first two sections (if it does not exists already), and moves the file into it.
  • if you want to see what the script is doing to each file, you can add option -v to the mv command. I used it to debug.

However, since it loops though each file one by one, this might take time with a large number of files, hence this next version.


V2

#!/bin/bash

while IFS= read -r dirname
do
    echo ">$dirname"

    # Create it if not already existing
    if [[ ! -d "$dirname" ]]
    then
        mkdir "$dirname"
    fi

    # Move the file into it
    find . -maxdepth 1 -type f -name "${dirname}_*" -exec mv {} "$dirname" \;
done < <(find . -maxdepth 1 -type f -name "*.jpg" -print | sed 's#^\./\(.*\)_\(.*\)_.*\..*$#\1_\2#' | sort | uniq)
  • this version loops on the directory names instead of on each file.
  • the last line does the "magic". It finds all files, and extracts the first two words (with sed) right away. Then these words are sorted and "uniqued".
  • the while loop then creates each directory one by one.
  • the find inside the while loop moves all files that match the directory being processed into it. Why did I not simply do mv ${dirname}_* ${dirname}? Since the expansion of the * wildcard could result in a too long arguments list for the mv command. Doing it with the find ensures that it will work even on LARGE number of files.

CodePudding user response:

Suggesting oneliner awk script:

echo "$(ls -1 *.jpg)"| awk '{system("mkdir -p "$1 OFS $2);system("mv "$0" "$1 OFS $2)}' FS=_ OFS=_

Explanation:

echo "$(ls -1 *.jpg)": List all jpg files in current directory one file per line

FS=_ : Set awk field separator to _ $1=type $2=fabric $3=color.jpg

OFS=_ : Set awk output field separator to _

awk script explanation

{ # for each file name from list
  system ("mkdir -p "$1 OFS $2); # execute "mkdir -p type_fabric"
  system ("mv " $0 " " $1 OFS $2); # execute "mv current-file to type_fabric"
}
  • Related