I got a bunch of directories with names like (I cannot change anything about go this are generated):
yyyy-MM-dd hh.mm.ss DIR1 File 01 random_number/
yyyy-MM-dd hh.mm.ss DIR2 File 06 random_number/
yyyy-MM-dd hh.mm.ss DIR3 File 11 random_number/
etc
where random_number
is a 11 digit random integer. Every directory has a file named something.ext
(the same name for every one). There is also a directory called done
where I move the directories that I already processed.
I rename the something.ext
files and copy them to another directory, manually like this:
cd yyyy-MM-dd\ hh.mm.ss\ DIR1\ File\ 01\ random_number/
mv something.ext File\ 01.ext
cp File\ 01.ext /path/to/DIR1/
cd ..
mv yyyy-MM-dd\ hh.mm.ss\ DIR1\ File\ 01\ random_number/ done/
cd yyyy-MM-dd\ hh.mm.ss\ DIR2\ File\ 06\ random_number/
mv something.ext File\ 06.ext
cp File\ 06.ext /path/to/DIR2/
cd ..
mv yyyy-MM-dd\ hh.mm.ss\ DIR2\ File\ 06\ random_number/ done/
etc
Is there any way i can automate this through a script? I'm not really good filtering names and stuff... I'm familiar with bash and python scripting...
CodePudding user response:
I'm assuming that all you have in the initial directory is your "bunch of directories" plus the done directory. Also, for testing purposes, I made the /path/to/
equal to ./done/
so that /path/to/DIR1/
is equal to ./done/DIR1/
, /path/to/DIR2/
is equal to ./done/DIR2/
, and so on. My test directory tree looks like this:
$ find .
.
./done
./done/DIR1
./done/DIR2
./done/DIR3
./yyyy-MM-dd hh.mm.ss DIR3 File 11 random_number
./yyyy-MM-dd hh.mm.ss DIR3 File 11 random_number/something.ext
./yyyy-MM-dd hh.mm.ss DIR2 File 06 random_number
./yyyy-MM-dd hh.mm.ss DIR2 File 06 random_number/something.ext
./yyyy-MM-dd hh.mm.ss DIR1 File 01 random_number
./yyyy-MM-dd hh.mm.ss DIR1 File 01 random_number/something.ext
$
You can achieve your mv
s and cp
s with a simple bash loop like this:
for i in *; do
if [ "$i" == "done" ]; then
continue;
fi;
file=$(echo $i | awk '{print $4 " " $5}').ext;
todir=./done/$(echo $i | awk '{print $3}');
mv "$i/something.ext" "$i/$file";
cp "$i/$file" "$todir";
mv "$i" done;
done
Here is the directory tree and files after running the script:
$ find .
.
./done
./done/DIR1
./done/DIR1/File 01.ext
./done/DIR2
./done/DIR2/File 06.ext
./done/DIR3
./done/DIR3/File 11.ext
./done/yyyy-MM-dd hh.mm.ss DIR1 File 01 random_number
./done/yyyy-MM-dd hh.mm.ss DIR1 File 01 random_number/File 01.ext
./done/yyyy-MM-dd hh.mm.ss DIR2 File 06 random_number
./done/yyyy-MM-dd hh.mm.ss DIR2 File 06 random_number/File 06.ext
./done/yyyy-MM-dd hh.mm.ss DIR3 File 11 random_number
./done/yyyy-MM-dd hh.mm.ss DIR3 File 11 random_number/File 11.ext
$
CodePudding user response:
You could use the =~
operator for regex pattern matching inside a for loop, which was a feature of bash starting from bashv3
. A subshell is useful when using cd
and not worrying if and when you need to exit the current directory.
#!/usr/bin/env bash
regex='^(. ) (. ) (. ) (. ) (. ) (. )$'
for directory in */; do
if [[ $directory =~ $regex ]]; then
dir_num0="${BASH_REMATCH[3]}"
dir_num1="${BASH_REMATCH[4]} ${BASH_REMATCH[5]}"
(
printf 'Going inside directory [%s]\n' "$directory"
cd "$directory" || exit
echo mv -v -- something.txt "$dir_num1.ext" || exit
echo cp -v -- "$dir_num1.ext" "/path/to/$dir_num0" || exit
)
echo mv -v -- "$directory" done/ || exit
fi
done
With your given sample input/data the output is:
Going inside directory [xxx-xx-xx xx.xx.xx DIR3 File 11 x/]
mv -v -- something.txt File 11.ext
cp -v -- File 11.ext /path/to/DIR3
mv -v -- xxx-xx-xx xx.xx.xx DIR3 File 11 x/ done/
Going inside directory [xxx-xx-xx xx.xx.xx DIR1 File 01 xx/]
mv -v -- something.txt File 01.ext
cp -v -- File 01.ext /path/to/DIR1
mv -v -- xxxx-xx-xx xx.xx.xx DIR1 File 01 x/ done/
Going inside directory [xxxx-xx-xx xx.xx.xx DIR2 File 06 x/]
mv -v -- something.txt File 06.ext
cp -v -- File 06.ext /path/to/DIR2
mv -v -- xxxx-xx-xx xx.xx.xx DIR2 File 06 x/ done/
The
=~
test/regex operator supports E.R.EPlace the script inside the directory in question and execute it. Or place the script within your
PATH
and go inside the top directory of the files/directories in question.Remove the
echo
's if you're satisfied with the output.The regex/pattern
regex='^(. ) (. ) (. ) (. ) (. ) (. )$'
matches 6 fields with a space as the delimiter/separator. It can be made more specific to your directory names.
Something like
regex='^([[:digit:]]{4}-[[:digit:]]{2}-[[:digit:]]{2}) ([[:digit:]]{2}\.[[:digit:]]{2}\.[[:digit:]]{2}) (. ) (. ) ([[:digit:]] ) ([[:digit:]] )/$'