Reputation: 305
I'm trying to find all files in a file structure above a certain file size, list them, then delete them. What I currently have looks like this:
filesToDelete=$(find $find $1 -type f -size +$2k -ls)
if [ -n "$filesToDelete" ];then
echo "Deleting files..."
echo $filesToDelete
$filesToDelete | xargs rm
else
echo "no files to delete"
fi
Everything works, except the $filesToDelete | xargs rm, obviously. Is there a way to use pipe on a variable? Or is there another way I could do this? My google-fu didn't really find anything, so any help would be appreciated.
Edit: Thanks for the information everyone. I will post the working code here now for anyone else stumbling upon this question later:
if [ $(find $1 -type f -size +$2k | wc -l) -ge 1 ]; then
find $1 -type f -size +$2k -exec sh -c 'f={}; echo "deleting file $f"; rm $f' {} \;
else
echo "no files above" $2 "kb found"
fi
Upvotes: 1
Views: 196
Reputation: 289495
You can directly use -exec
to perform an action on the files that were found in find
:
find $1 -type f -size +$2k -exec rm {} \;
The -exec
trick makes find
execute the command given for each one of the matches found. To refer the match itself we have to use {} \;
.
If you want to perform more than one action, -exec sh -c "..."
makes it. For example, here you can both print the name of the files are about to be removed... and remove them. Note the f={}
thingy to store the name of the file, so that it can be used later on in echo
and rm
:
find $1 -type f -size +$2k -exec sh -c 'f={}; echo "removing $f"; rm $f' {} \;
In case you want to print a message if no matches were found, you can use wc -l
to count the number of matches (if any) and do an if / else
condition with it:
if [ $(find $1 -type f -size +$2k | wc -l) -ge 1 ]; then
find $1 -type f -size +$2k -exec rm {} \;
else
echo "no matches found"
fi
wc
is a command that does w
ord c
ount (see man wc
for more info). Doing wc -l
counts the number of l
ines. So command | wc -l
counts the number of lines returned by command
.
Then we use the if [ $(command | wc -l) -ge 1 ]
check, which does an integer comparison: if the value is g
reater or e
qual to 1
, then do what follows; otherwise, do what is in else
.
Buuuut the previous approach was using find
twice, which is a bit inefficient. As -exec sh -c
is opening a sub-shell, we cannot rely on a variable to keep track of the number of files opened. Why? Because a sub-shell cannot assign values to its parent shell.
Instead, let's store the files that were deleted into a file, and then count it:
find . -name "*.txt" -exec sh -c 'f={}; echo "$f" >> /tmp/findtest; rm $f' {} \;
if [ -s /tmp/findtest ]; then #check if the file is empty
echo "file has $(wc -l < /tmp/findtest) lines"
# you can also `cat /tmp/findtest` here to show the deleted files
else
echo "no matches"
fi
Note that you can cat /tmp/findtest
to see the deleted files, or also use echo "$f"
alone (without redirection) to indicate while removing. rm /tmp/findtest
is also an option, to do once the process is finished.
Upvotes: 1
Reputation: 2382
You don't need to do all this. You can directly use find
command to get the files over a particular size limit and delete it using xargs.
This should work:
#!/bin/bash
if [ $(find $1 -type f -size +$2k | wc -l) -eq 0 ]; then
echo "No Files to delete"
else
echo "Deleting the following files"
find $1 -size +$2 -exec ls {} \+
find $1 -size +$2 -exec ls {} \+ | xargs rm -f
echo "Done"
fi
Upvotes: 1
Reputation: 241748
As already pointed out, you don't need piping a var in this case. But just in case you needed it in some other situation, you can use
xargs rm <<< $filesToDelete
or, more portably
echo $filesToDelete | xargs rm
Beware of spaces in file names.
To also output the value together with piping it, use tee
with process substitution:
echo "$x" | tee >( xargs rm )
Upvotes: 4