Bash Scripting – Move Every File That Is Not a Directory

bashdirectorymvwildcards

I have a directory that I am trying to clean out that contains both files and subdirectories. What I am trying to do is simple: move all the files into another directory, but leave all the sub-directories as they are.

I am thinking something like:

mv [*_but_no_dirs] ./other_directory

It seems like there should be a simple way to do this with wildcards * and regex…

Anyone have ideas?

Best Answer

Regex aren't involved here. Wildcards in bash (like most other shells) only match files based on the file names, not based on the file type or other characteristics. There is one way to match by type: adding / at the end of the pattern makes it only match directories or symbolic links to directories. This way, you can move directories, then move what's left, and move directories back — cumbersome but it works.

tmp=$(TMPDIR=.. mktemp -d)
mv -- */ "$tmp"
mv -- * other_directory/
mv "$tmp"/* .
rmdir "$tmp"

(that approach should be avoided if the current directory is the mount point of a filesystem, as that would mean the moving of directories away and back would have to copy all the data in there twice).

A standard way to match files by type is to call find.

find . -name . -o -type d -prune -o -exec sh -c 'mv "$@" "$0"' other_directory/ {} +

(also moves symlinks, whether they point to directories or not).

In zsh, you can use glob qualifiers to match files by type. The . qualifier matches regular files; use ^/ to match all non-directories, or -^/ to also exclude symbolic links to directories.

mv -- *(.) other_directory/

In any shell, you can simply loop.

for x in *; do
   if ! [ -d "$x" ]; then
     mv -- "$x" other_directory/
   fi
done

(does not move symlinks to directories).

Related Question