Home > Software engineering >  moving files with patron in directories to specific directory
moving files with patron in directories to specific directory

Time:09-28

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 mvs and cps 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.E

  • Place 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:]] )/$'
  • Related