Reputation: 511
I have a lot of directories; a lot of them have just 1 file or 2 in them.
I want to copy the directories which have more than 2 files in them in another directory, how can I check it and move the directories?
I have come so far with the script but I'm not sure of it.
#!/bin/bash
mkdir "subset"
for dir in *; do
#if the file is a directory
if [ -d "$dir" ]; then
#count number of files
count=$(find "$dir" -type f | wc -l)
#if count>=2 then move
if [ "$count" -ge 2 ]; then
#move dir
# ...
fi
fi
done
The command mv $dir ..
moves the directory up of one, but is it possible to move up of one and down in subset
without using complete path mv $dir complete_path/subset
?
Upvotes: 1
Views: 97
Reputation: 8174
There are many traps and pitfalls if you want to handle arbitrary directory names and contents. This Shellcheck-clean code tries to avoid all of them:
#! /bin/bash -p
shopt -s nullglob # glob patterns that match nothing expand to nothing
shopt -s dotglob # glob patterns expand names that start with '.'
destdir='subset'
[[ -d $destdir ]] || mkdir -- "$destdir"
for dir in * ; do
[[ -L $dir ]] && continue # Skip symbolic links
[[ -d $dir ]] || continue # Skip non-directories
[[ $dir -ef $destdir ]] && continue # Skip the destination dir.
numfiles=$(find "./$dir//." -type f -print | grep -c //)
(( numfiles > 2 )) && mv -v -- "$dir" "$destdir"
done
shopt -s nullglob
means that the code will work if run in an empty directory. (Otherwise it will try to process a spurious directory entry called '*'.)shopt -s dotglob
enables the code to handle directories whose names begin with '.' (e.g. .mydir
).for dir in */ ...
, but that would slightly complicate the check for symbolic links.[[ -L $dir ]] && continue
). Remove the line if that assumption is not correct.find ... | wc -l
might not work correctly. See How can I get a count of files in a directory using the command line?.find
("./$dir//."
) is designed to avoid several pitfalls. The quotes prevent special characters in directory names causing problems. The ./
prefix avoids the argument being treated as an option if the directory name starts with -
. The //.
suffix means that there will be exactly one '//' on a line for every file found by find
, so grep -c //
will accurately count the number of files.--
argument to the mkdir
and mv
commands is to ensure that they work correctly if $dir
or $destdir
begins with a -
(which would cause them to be treated as options). See Bash Pitfalls #2 (cp $file $target).Upvotes: 4
Reputation: 361889
Your general approach is fine. There's no clearly superior way to count how many files are in a directory, unfortunately.
You can get rid of the -d
check by looping over */
. The trailing /
means only directories will match.
You could combine the assignment and test. You may like it or may find it weird looking.
You could also use ((...))
to do arithmetic. I find it a bit more readable, personally.
for dir in */; do
if count=$(find "$dir" -type f | wc -l) && ((count >= 2)); then
...
fi
done
Or you could elide the count
variable entirely.
for dir in */; do
if (($(find "$dir" -type f | wc -l) >= 2)); then
...
fi
done
It's possible to do all of this in a single find
invocationbut now we're definitely in arcane territory.
find . -type d \
-exec bash -c '(($(compgen -G "$1/*" | wc -l) > 2))' bash {} \; \
-exec mv {} subset/ \;
The command
mv $dir ..
moves the directory up of one, but is it possible to move up of one and down insubset
without using complete pathmv $dir complete_path/subset
?
You haven't change directories so use whatever relative path you like. If I understand the question, it might be as simple as mv <dir> subset/
.
Upvotes: 0
Reputation: 511
This is the best solution I've come so far.
I wanted to know if there is a more elegant solution:
#!/bin/bash
mkdir "OOOO3_LESS_THAN_TWO"
for dir in *; do
#if the file is a directory
if [ -d "$dir" ]; then
#count number of files
count=$(find "$dir" -type f | wc -l)
#if count<=2 then move
if [ "$count" -le 2 ]; then
#move dir
mv -v "$dir" /completepath/"OOOO3_LESS_THAN_TWO"
fi
fi
done
Upvotes: 0