Move files according to pattern matching

I have some files whose name looks like this:

XXXXX_S1_X_XX_X.txt
XXXXX_S2_X_XX_X.txt
XXXXX_S3_X_XX_XXX.txt
S4_X_XX_X.txt
XXXXX_S5_XX_X.txt   
...

I created a list of folders named: S1, S2, S3, …. I would like to move the file XXXXX_S1_X_XX_X.txt in the folder S1, the file XXXXX_S2_X_XX_X.txt in the folder S2 and so on. I wrote this simple loop but I don’t know how to copy/move files according to the pattern matching S* in the corresponding folder:

for i in My_list_of_folders.txt
do 
  dir=${i%.txt}
  mkdir "$dir"
  cp "$i" "$dir"
done

Answer

A slightly modified loop:

for pattern in S1 S2 S3 S4; do
   mkdir -p ./"$pattern"
   for filename in ./*"$pattern"*; do
       [ ! -f "$filename" ] && continue
       mv -i "$filename" "$pattern"/
   done
done

This loops through the pattern strings S1, S2, S3 and S4. The inner loop uses the current pattern string to look for names in the current directory that contains the string anywhere in it. It skips non-regular files (like the directories S1, S2 etc. themselves) and moves everything else that matches to the appropriate directory for that pattern string.

As slm points out in comments (now deleted), the operations in the inner loop may in this case well be shortened into just

[ ! -f "$filename" ] || mv -i "$filename" "$pattern"/

or

[ -f "$filename" ] && mv -i "$filename" "$pattern"/

If you have overlapping patterns, such as S1 and S11, then you will need to do the longer patterns first.

Leave a Reply

Your email address will not be published. Required fields are marked *