How to use find to copy and remove directories? - shell

I am trying to find the files which are older than some days and i want to copy the files to the specific folder and to remove the files from the source directory in a single command.
find . -type d -mtime +600 -exec cp -rf '{}' destination folder \; -exec rm -rf '{}' \;
Error:
find: ./one: No such file or directory
find: ./two: No such file or directory
find: ./three: No such file or directory
How can I resolve the error?

Try something like:
find . -type d -mtime -600 -exec cp -rf '{}' destination_folder \; -delete
Alternatively, you could even use
find . -type d -mtime -600 -print0 -exec cp -rf '{}' destination_folder \; | xargs -0 rm -rf

I'm not quite sure why you're doing cp and rm, rather than the much faster mv?
But, you can largely ignore that error, find pre-processes part of the tree, if you want to force it to ignore the removed subdirectories add -prune (you probably should quote destination dir)
find . -type d -mtime +600 -exec cp -rf '{}' 'destination folder' \; -exec rm -rf '{}' \; -prune
.
-prune True; if the file is a directory, do not descend into it. If -depth is given, false; no effect.
Because -delete implies -depth, you cannot usefully use -prune and -delete together.

Related

GNU find following symbolic links and name pattern fails to execute remove (rm)

I tried to remove files which might be located in symlinked directories. I recognized for certain basenames, that find fails with the error No such file or directory.
Here is what I tried. Am I doing something wrong? Thanks!
touch a_b.c.d
touch a_b.d
find -L . -type f -name '*.c.d' -exec bash -c 'rm $(basename {} .c.d).d' \;
This fails, too
touch a_b.c.d
touch a_b.d
find -L . -type f -name '*.c.d' -exec rm a_b.d \;
But this works
touch a_x_b.c.d
touch a_x_b.d
find -L . -type f -name '*.c.d' -exec bash -c 'rm $(basename {} .c.d).d' \;
or this, respectively
touch a_x_b.c.d
touch a_x_b.d
find -L . -type f -name '*.c.d' -exec rm a_x_b.d \;

How to print the deleted file names along with path in shell script

I am deleting the files in all the directories and subdirectories using the command below:
find . -type f -name "*.txt" -exec rm -f {} \;
But I want to know which are the files deleted along with their paths. How can I do this?
Simply add a -print argument to your find.
$ find . -type f -name "*.txt" -print -exec rm -f {} \;
As noted by #JonathanRoss below, you can achieve an equivalent result with the -v option to rm.
It's not the scope of your question, but more generally it gets more interesting if you want to delete directories recursively. Then:
a simple -exec rm -r argument keeps it silent
a -print -exec rm -r argument reports the toplevel directories you're operating on
a -exec rm -rv argument reports all you're removing

Delete directories with specific files in Bash Script

I would like to delete specific files if existed but also the directories that contain these files. I do know the files I would like to wipe but not the directories. So far, as I'm new in bash scripting, I think of this :
find ./ -type f -name '*.r*' -print0 | xargs -0 rm -rf &> log_del.txt
find ./ -type f -name '*.c*' -print0 | xargs -0 rm -rf &>> log_del.txt
At the moment, all files named with the specific extensions *.r* and *.c* are deleted.
But the directories are still remaining and also the subdirectories in it, if existed.
I also thought of the option -o in find to delete in one line :
find ./ -type f \( -name '*.r*' -o -name '*.c*' \) -print0 | xargs -0 rm -rf &> log_del.txt
How can I do this?
And I also see that my log_del.txt file is empty... :-(
It looks like what you really want is to remove all empty directories, recursively.
find . -type d -delete
-delete processes the directories in child-first order, so that a/b is deleted before a. If a given directory is not empty, find will just display an error and continue.
If the directories remain empty, let rmdir try to remove all of them. It will fail on any directories which have still files.
find ./ -type d -exec rmdir --ignore-fail-on-non-empty {} 2>/dev/null \;
See if this serves your requirement:
find ./ -type f -name '*.r*' -delete -printf "%h\0" | xargs -0 rmdir
If the directory contained any other files, rmdir will fail.
So consider below sample file structure:
$ find a
a/
a/a/
a/a/4
a/b/
a/b/5
a/b/4
a/b/3
a/b/2
a/b/1
$ find a -type f -name '4' -delete -printf "%h\0" | xargs -0 -r rmdir
rmdir: failed to remove ‘a/b’: Directory not empty
$ find a
a
a/b
a/b/5
a/b/3
a/b/2
a/b/1
If in above example, you want to delete directory b also, you can simply use:
$ find ./ -type f -name '*.r*' -printf "%h\0" | xargs -0 rm -rf
EDIT: As per the comment, you (OP) wanted that the empty directory tree should also be deleted. These 2 commands should help you then:
$ find ./ -type f -name '*.r*' -delete # Delete matching files
$ find ./ -empty -type d -delete # Delete tree of empty directories

Delete all hidden files in folder and subfolders

I need to delete all hidden files in the current folder and its sub folders. Is there any way to do it with a single line command without creating a script?
Use
find "$some_directory" -type f -name '.*' -delete
If you want to remove hidden directories as well, you'll need to take a little more care to avoid . and .., as mentioned by Ronald.
find "$some_directory" -name '.*' ! -name '.' ! -name '..' -delete
With either command, you should run without the -delete primary first, to verify that the list of files/directories that find returns includes only files you really want to delete.
For completeness, I should point out that -delete is a GNU extension to find; the POSIX-compliant command would be
find "$some_directory" -type f -name '.*' -exec rm '{}' \;
i.e., replace -delete with -exec ... \;, with ... replaced with the command line you would use to remove a file, but with the actual file name replaced by '{}'.
For my Netgear Stora, I wanted to remove all the hidden .webview .thumbnails .AppleDouble etc files and folders.
This works from the /home/yourusername/ folder:
find -type f -name '.*' ! -name '.' ! -name '..' -exec rm -fv '{}' \;
and then
find -type d -name '.*' ! -name '.' ! -name '..' -exec rm -frdv '{}' \;

Why is this command exploding

So I got this as an answer to a previous question as an answer for looking recursively through files in a directory and deleting the files and directories if found:
find \( -name ".git" -o -name ".gitignore" -o -name "Documentation" \) -exec rm -rf "{}" \;
There are two problems with this:
One:
find: `./adam.balan/AisisAjax/.git': No such file or directory
because of this error the rest of the script doesn't execute. Now I don't want to have to check for any of the files or folders. I don't care if they exist or not, I want to suppress the error on this.
The second is that I am also getting the error on a directory that needs to be excluded from this search: vendor/
find: `./vendor/adam.balan/AisisAjax/.git': No such file or directory
I do not want it searching vendor. I want it to leave vendor alone.
How do I solve these two problems? Suppression and ignoring.
The problem is that you're deleting a directory that find then tries to descend into. You can use -prune to prevent that:
find \( -name ".git" -o -name ".gitignore" -o -name "Documentation" \) -prune -exec rm -rf "{}" \;
To ignore all errors, you can use 2> /dev/null to squash the error messages, and || true to avoid set -e making your script exit:
find \( -name ".git" -o -name ".gitignore" -o -name "Documentation" \) -prune -exec rm -rf "{}" \; 2> /dev/null || true
Finally, to avoid descending any directory named 'vendor', you can use -prune again:
find -name vendor -prune -o \( -name ".git" -o -name ".gitignore" -o -name "Documentation" \) -prune -exec rm -rf "{}" \; 2> /dev/null || true

Resources