Search code examples
bashshellglob

How to move files en-masse while skipping a few files and directories


I'm trying to write a shell script that moves all files except for the ones that end with .sh and .py. I also don't want to move directories.

This is what I've got so far:

cd FILES/user/folder
shopt -s extglob
mv !(*.sh|*.py) MoveFolder/ 2>/dev/null 
shopt -u extglob

This moves all files except the ones that contain .sh or .py, but all directories are moved into MoveFolder as well.

I guess I could rename the folders, but other scripts already have those folders assigned for their work, so renaming might give me more trouble. I also could add the folder names but whenever someone else creates a folder, I would have to add its name to the script or it will be moved as well.

How can I improve this script to skip all folders?


Solution

  • Use find for this:

    find -maxdepth 1 \! -type d \! -name "*.py" \! -name "*.sh" -exec mv -t MoveFolder {} +
    

    What it does:

    • find: find things...
    • -maxdepth 1: that are in the current directory...
    • \! -type d: and that are not a directory...
    • \! -name "*.py: and whose name does not end with .py...
    • \! -name "*.sh: and whose name does not end with .sh...
    • -exec mv -t MoveFolder {} +: and move them to directory MoveFolder

    The -exec flag is special: contrary to the the prior flags which were conditions, this one is an action. For each match, the + that ends the following command directs find to aggregate the file name at the end of the command, at the place marked with {}. When all the files are found, find executes the resulting command (i.e. mv -t MoveFolder file1 file2 ... fileN).