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 thedirname
as well (that is what thesed
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 themv
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
find
s all files, and extracts the first two words (withsed
) right away. Then these words aresort
ed and "uniq
ued". - the
while
loop then creates each directory one by one. - the
find
inside thewhile
loop moves all files that match the directory being processed into it. Why did I not simply domv ${dirname}_* ${dirname}
? Since the expansion of the*
wildcard could result in a too long arguments list for themv
command. Doing it with thefind
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"
}