We recently ran into an issue where there were legacy all-caps files in a directory, and we needed to move them. The remaining files were all lower-case. It turns out that when there are subdirectories involved, it is not as easy to move just the all-caps files, rather than the subdirectories. Here is an example file structure:
usr-1@srv-1 movefiles $ find . . ./listf.sh ./capmv.sh ./Y ./Y/B ./Y/b ./Y/A ./Y/a ./Z ./Z/a ./Z/A ./Z/B ./Z/b ./X ./B ./a ./A ./b usr-1@srv-1 movefiles $ |
We have upper and lower case filenames in the current directory, as well as in Y and Z. The X directory is empty. Now, you would think that you could simply look at all of the files in the current directory and move the ones with the first character being a cap. For instance, let’s list all of the files that are specified as [A-Z]*:
usr-1@srv-1 movefiles $ ls [A-Z]* A B X: Y: A B a b Z: A B a b usr-1@srv-1 movefiles $ |
Hmmm… if we were to move these with mv, we would get the subdirectories. Let’s put this in a bash script so we can operate on the files individually. A script like this should work (using mv instead of ls):
usr-1@srv-1 movefiles $ cat listf.sh for i in [A-Z]*; do ls -R $i done usr-1@srv-1 movefiles $ |
The -R lists the directories as it encounters them. This doesn’t work, though:
usr-1@srv-1 movefiles $ sh listf.s A B X: Y: A B a b Z: A B a b usr-1@srv-1 movefiles $ |
What we want are just the files, not the directories. We can add an additional test. The -f test is true if the file exists and is a regular file. Here is a script that works to move all files with the first letter being a cap to the X subdirectory:
usr-1@srv-1 movefiles $ cat capmv.sh for i in [A-Z]*; do if [ -f $i ]; then mv $i X fi done usr-1@srv-1 movefiles $ usr-1@srv-1 movefiles $ sh capmv.sh usr-1@srv-1 movefiles $ find . . ./listf.sh ./capmv.sh ./Y ./Y/B ./Y/b ./Y/A ./Y/a ./Z ./Z/a ./Z/A ./Z/B ./Z/b ./X ./X/A ./X/B ./a ./b usr-1@srv-1 movefiles $ |
Note that A and B are now in the X directory. The space before the -f in the brackets is required.