0

I am quite new at using Linux and the terminal and I am stuck with something.

I have about 50 parent folders, all containing subfolders. One subfolder is called filtered_feature_bc_matrix. In an other subfolder, there are some .mtx or .tsv files, that I would like to move in the filtered_feature_bc_matrix subfolder.

So my architecture is like that

Mother_folder(containing all the 50 parent folders) ->   
   parent_folder          
       ->filtered_feature_bc_matrix                
       ->other_subfolder
          ->other_subsubfolder
               files.mtx

I tried:

for dir in ./; do
  $(find . -type f -name *.mtx -exec mv {} "./$dir/filtered_feature_bc_matrix" \;);
done

I succeed if I cd inside the parent folder, but I have 50 of them, so I would like to understand how to automate this task.

But I cannot specify the target directory properly, and that drives me crazy ;-)

I hope I am clear!

Camille

Edit:

And when I execute the code, I have the file matrix.mtx actually moved not in the subfolder I want, but in the mother_folder and renames filtered_feature_bc_matrix...

2
  • -name *.mtx will expand to all files in the current directory that match this glob, you probably want -name '*.mtx' to prevent that. $() is also unneccesary, as will try to execute whatever is returned as a command.
    – Panki
    Nov 30, 2023 at 15:23
  • Also, you probably don't want find ., but find "$dir" instead. I recommend using shellcheck.net
    – Panki
    Nov 30, 2023 at 15:25

1 Answer 1

0

With zsh:

autoload zmv
cd /path/to/mother/folder &&
  zmv -n '*/^filtered_feature_bc_matrix/**/*.(mtx|tsv)(#q.)' \
         '${f:h1}/filtered_feature_bc_matrix/${f:t}'

(remove the -n (dry-run) if happy).

With find and from a Bourne-like or rc-like shell, you could do something approaching with:

cd /path/to/mother/folder &&
  LC_ALL=C find .                             \
    '('                                       \
       -name '.?*' -o                         \
       -path './*/filtered_feature_bc_matrix' \
          ! -path './*/*/*'                   \
    ')' -prune -o                             \
    -path './*/*/*'                           \
    '('                                       \
       -name '*.tsv' -o                       \
       -name '*.mtx'                          \
    ')' -type f                               \
    -exec sh -c '
      ret=0
      for file do
        parent=${file%"${file#./*/}"}
        echo mv -i -- "$file" "${parent}filtered_feature_bc_matrix/" ||
          ret=$?
      done
      exit "$ret"' sh {} +

(remove the echo if happy).

Though that's without the safeguards of zmv. The -i option should help prevent losing data though.

1
  • That works great! thank you very much. I have a lot of progress to make to be able to code something like that! Dec 1, 2023 at 10:16

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .