Recursively find directories by a specific name and then clear them - linux

Suppose that the following project structure is given:
/
|
|- /bin
|- /src
|
|- /bin
|- abc
...
|
|- /bin
and I would like to erase the contents of the bin subdirectories, but not delete them. How do I achieve tis through the Bash command line?
EDIT
I have tried find . -regex bin/* -type d -exec rm -rf {} \;, but to no avail.

I suggest with GNU find:
find . -regex ".*/bin/.*" -type f -exec echo rm {} \;
if everything looks fine remove echo.

When you want to delete files, it is unnecessary (indeed dangerous) to pass -r to rm.
Besides, find "knows" how to delete, without the need to call rm in the first place.
find . -type f -wholename "*/bin/*" -delete

Debug your command: try each argument to find in isolation to see if it is producing expected output.
We quickly see that
find . -regex bin/*
doesn't work because of an issue in regex. If we check the man for find, we see that the regex must match the full path:
-regex pattern
File name matches regular expression pattern. This is a match
on the whole path, not a search. For example, to match a file
named ./fubar3', you can use the regular expression.*bar.'
or .*b.*3', but notf.*r3'.
This should do the job:
find . -regex '".*/bin/.*"' -type d -delete
or using your command:
find . -regex '".*/bin/.*"' -type d -prune -exec rm -rf {} \;
Remember to quote your expressions to avoid unexpected shell expansion.

Related

Linux deleteing a folder's content

I can find ./ -type d -name "Debug" -exec rm -f {} + to delete the fold and content.
My question is: How to fine all "Debug" folders and ONLY delete the content and Not the folder?
#!/bin/bash
find . -type d -name "Debug" -print | xargs -I% find % -maxdepth 1 -type f -delete
the first find lists all Debug directories
xargs defines the "%" symbol as what is replaced by the received stdin. You will often see -I{} for xargs, but I chose another string since you might need {} in the find. Any char will do.
the second find, in directory "%" (so here one of the Debug directories received from the first find), deletes all files under that directory.
-maxdepth 1 is used in the second find to make sure it only deletes the files in the current Debug directory, and does not recursively deletes all files.

Write a script that deletes all the regular files (not the directories) with a .js extension that are present in the current directory and all its sub [duplicate]

I'm trying to work out a command which deletes sql files older than 15 days.
The find part is working but not the rm.
rm -f | find -L /usr/www2/bar/htdocs/foo/rsync/httpdocs/db_backups -type f \( -name '*.sql' \) -mtime +15
It kicks out a list of exactly the files I want deleted but is not deleting them. The paths are correct.
usage: rm [-f | -i] [-dIPRrvW] file ...
unlink file
/usr/www2/bar/htdocs/foo/rsync/httpdocs/db_backups/20120601.backup.sql
...
/usr/www2/bar/htdocs/foo/rsync/httpdocs/db_backups/20120610.backup.sql
What am I doing wrong?
You are actually piping rm's output to the input of find. What you want is to use the output of find as arguments to rm:
find -type f -name '*.sql' -mtime +15 | xargs rm
xargs is the command that "converts" its standard input into arguments of another program, or, as they more accurately put it on the man page,
build and execute command lines from standard input
Note that if file names can contain whitespace characters, you should correct for that:
find -type f -name '*.sql' -mtime +15 -print0 | xargs -0 rm
But actually, find has a shortcut for this: the -delete option:
find -type f -name '*.sql' -mtime +15 -delete
Please be aware of the following warnings in man find:
Warnings: Don't forget that the find command line is evaluated
as an expression, so putting -delete first will make find try to
delete everything below the starting points you specified. When
testing a find command line that you later intend to use with
-delete, you should explicitly specify -depth in order to avoid
later surprises. Because -delete implies -depth, you cannot
usefully use -prune and -delete together.
P.S. Note that piping directly to rm isn't an option, because rm doesn't expect filenames on standard input. What you are currently doing is piping them backwards.
find /usr/www/bar/htdocs -mtime +15 -exec rm {} \;
Will select files in /usr/www/bar/htdocs older than 15 days and remove them.
Another simpler method is to use locate command. Then, pipe the result to xargs.
For example,
locate file | xargs rm
Use xargs to pass arguments, with the option -rd '\n' to ignore spaces in names:
"${command}" | xargs -rd '\n' rm
Include --force if you want to also remove read only files.
Assuming you aren't in the directory containing the *.sql backup files:
find /usr/www2/bar/htdocs/foo/rsync/httpdocs/db_backups/*.sql -mtime +15 -exec rm -v {} \;
The -v option above is handy it will verbosely output which files are being deleted as they are removed.
I like to list the files that will be deleted first to be sure. E.g:
find /usr/www2/bar/htdocs/foo/rsync/httpdocs/db_backups/*.sql -mtime +15 -exec ls -lrth {} \;

Remove content of many subfolders that are names equally

My folder structure looks like this:
|-20200912
-fringe
-other
|-20200915
-fringe
-other
...
And I want to delete the content of all folders called "fringe". How could I achieve this with one command?
I thought about something like this in pseudocode:
find . -name "fringe" -type d -exec rm <content>
You were close.
find . -name 'fringe' -type d -exec rm -rf {} +
This removes every directory named fringe and everything within them.
Single vs double quotes don't make a difference here, but generally prefer single quotes if you mean to pass something in verbatim (with the possible exception of when the thing you want to pass in contains literal single quotes).
If you want to remove the directory's contents, try
... -execdir sh -c 'rm '*' \;
You are looking to process the files and not the directory through rm and so I would use a regex that searches for for files with fringe in the directory path.
find -regex "^.*/fringe/.*$" -type f -exec rm '{}' \;
I would change the rm to ls to ensure that the results are expected before running the actual rm.
You can force gobbing in the exec command:
find -name fringe -type d -execdir sh -c 'rm {}/*' \;

Bash: Find files containing a certain string and copy them into a folder

What I want:
In a bash script: Find all files in current directory that contain a certain string "teststring" and cop them into a subfolder "./testfolder"
Found this to find the filenames which im looking for
find . -type f -print0 | xargs -0 grep -l "teststring"
..and this to copy found files to another folder (here selecting by strings in filename):
find . -type f -iname "stringinfilename" -exec cp {} ./testfolder/ \;
Whats the best way to combine both commands to achieve what I described at the top?
Just let find do both:
find . -name subdir -prune -o -type f -exec \
grep -q teststring "{}" \; -exec cp "{}" subdir \;
Note that things like this are much easier if you don't try to add to the directory you're working in. In other words, write to a sibling dir instead of writing to a subdirectory. If you want to wind up with the data in a subdir, mv it when you're done. That way, you don't have to worry about the prune (ie, you don't have to worry about find descending into the subdir and attempting to duplicate the work).

Linux command for removing all ~ files

What command can I use in Linux to check if there is a file in a given directory (or its subdirectories) that contains a ~at the end of the file's name?
For example, if I'm at a directory called t which contains many subdirectories, etc, I would like to remove all files that end with a ~.
Watch out for filenames with spaces in them!
find ./ -name "*~" -type f -print0 | xargs -0 rm
with GNU find
find /path -type f -name "*~" -exec rm {} +
or
find /path -type f -name "*~" -delete
find ./ -name '*~' -print0 | xargs -0 rm -f
Here find will search the directory ./ and all sub directories, filtering for filenames that match the glob '*~' and printing them (with proper quoting courtesy of alberge). The results are passed to xargs to be appended to rm -f and the resulting string run in a shell. You can use multiple paths, and there are many other filters available (just read man find).
you can use a find, grep, rm combination, something like
find | grep "~" | xargs rm -f
Probably others have better ideas :)

Resources