Bash delete all folders except some - bash

I have a directory with this structure:
main/
Antispam/res/values/
strings.xml
plurarls.xml
arrays.xml
Backup/res/values/
strings.xml
plurarls.xml
arrays.xml
etc.
Antispam and Backup have other folders inside, but I do not need those. I just want to have only the values folder with the three XML files (strings.xml, plurarls.xml and arrays.xml). How can I do that?

if you run this in the parent directory:
find . -regex '.*backup.*'
you would have something like this:
./backup
./backup/res
./backup/res/value
./backup/res/value/00.xml
./backup/res/value/02.xml
./backup/res/value/01.xml
And then you can invert the match by -not
find . -not -regex '.*backup.*'
and of course you can make it more specific with -type d and literal ./
find . -type d -not -regex './backup.*'
and then do any thing you like with the output

This is what I would do. Basically just find folders excluding the parent folders and send them to oblivion.
find main/Antispam/res/values/ '!' -path main/Antispam/res/values/ -type d | xargs rm -f -r $1
find main/Backup/res/values '!' -path main/Backup/res/values -type d | xargs rm -f -r $1
Hope it works for you! :)

This work for me:
ale8530#vmi81507:~/Scrivania/APK-Tools-Linux-master/working$ find . -regex '.*res/values/strings.*'
./WaliLive/res/values/strings.xml ./SystemAdSolution/res/values/strings.xml ./SampleExtAuthService/res/values/strings.xml ./DocumentsUI/res/values/strings.xml ./CaptivePortalLogin/res/values/strings.xml ./SoundRecorder/res/values/strings.xml ./ExternalStorageProvider/res/values/strings.xml ./MiuiCompass/res/values/strings.xml ./CloudBackup/res/values/strings.xml ./BackupRestoreConfirmation/res/values/strings.xml ./AntHalService/res/values/strings.xml ./MiuiSuperMarket/res/values/strings.xml ./DownloadProvider/res/values/strings.xml ./VpnDialogs/res/values/strings.xml ./XiaomiAccount/res/values/strings.xml ./SpacesCore/res/values/strings.xml ./CdmaCallOptions/res/values/strings.xml
Can you copy this output to another director
y? Keeping the same output?
For example
From-->./WaliLive/res/values/strings.xml to ./WaliLive.apk/res/values/strings.xml
Thanks

PLEASE BACKUP YOU DATA BEFORE YOU TRY!!!
if you don't care about empty dirs (or you don't care to do everything with one command), i'll do something like:
find ! -name strings.xml ! -name plurarls.xml ! -name arrays.xml -type f -delete
if you care about empty dirs:
find -type d -print0 | xargs -0 rmdir -p

Related

Remove empty files and save a list of deleted files

I need a script that removes all empty files and writes a list of deleted files to a text file.
Deleting files works. Unfortunately, the listing does not work.
find . -type f -empty -print -delete
I tried something like this:
-print >> test.txt
When I redirect the output of your command to a file in ., it gets delete by the find command before anything is written to it, since it is empty.
To solve this, make sure the output file is not empty at the beginning, or save it elsewhere:
find . -type f -empty -print -delete > ../log
or
date > log
find . -type f -empty -print -delete >> log
or, adapted from #DanielFarrell's comment:
find . -type f -empty -a -not -wholename ./log -print -delete > log
The added -a -not -wholename ./log excludes ./log from the find operation.
You can use -exec option with rm command instead of -delete.
find . -type f -emtpy -exec rm --verbose {} \; >> logfile.txt
logfile.txt:
removed './emptyfile1'
removed './emptyfile0'
Or you can use pipes and xargs for a more clean output:
find . -type f -empty | xargs ls | tee -a logfile.txt | xargs rm
This will give you only deleted filenames.

Bash script for removing specific file from certain subdirectories

On a unix server, I'm trying to figure out how to remove a file, say "example.xls", from any subdirectories that start with v0 ("v0*").
I have tried something like:
find . -name "v0*" -type d -exec find . -name "example.xls" -type f
-exec rm {} \;
But i get errors. I have a solution but it works too well, i.e. it will delete the file in any subdirectory, regardless of it's name:
find . -type f -name "example.xls" -exec rm -f {} \;
Any ideas?
You will probably have to do it in two steps -- i.e. first find the directories, and then the files -- you can use xargs to make it in a single line, like
find . -name "v0*" -type d | \
xargs -l -I[] \
find [] -name "example.xls" -type f -exec rm {} \;
what it does, is first generating a list of viable directory name, and let xargs call the second find with the names locating the file name within that directory
Try:
find -path '*/v0*/example.xls' -delete
This matches only files named example.xls which, somewhere in its path, has a parent directory name that starts with v0.
Note that since find offers -delete as an action, it is not necessary to invoke the external executable rm.
Example
Consider this directory structure:
$ find .
.
./a
./a/example.xls
./a/v0
./a/v0/b
./a/v0/b/example.xls
./a/v0/example.xls
We can identify files example.xls who have one of their parent directories named v0*:
$ find -path '*/v0*/example.xls'
./a/v0/b/example.xls
./a/v0/example.xls
To delete those files:
find -path '*/v0*/example.xls' -delete
Alternative: find only those files directly under directory v0*
find -regex '.*/v0[^/]*/example.xls'
Using the above directory structure, this approach returns one file:
$ find -regex '.*/v0[^/]*/example.xls'
./a/v0/example.xls
To delete such files:
find -regex '.*/v0[^/]*/example.xls' -delete
Compatibility
Although my tests were performed with GNU find, both -regex and -path are required by POSIX and also supported by OSX.

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

recursively delete all files except some especific types

I want to recursively delete all files in some folders except those who have .gz extension. Normally I use
find /thepath -name "foo" -print0 | xargs -0 rm -rf
to recursively delete all folders named "foo" in the /thepath. But now I wan to add an exclusion option. How that is possible?
For example, the folder structure looks like
.hiddenfolder
.hiddenfolder/bin.so
arc.tar.gz
note.txt
sample
So I want to delete everything but keep arc.tar.gz
Find and delete all files under /thepath except with name matching *.gz:
# First check with ls -l
find /thepath -type f ! -name '*.gz' -print0 | xargs -0 ls -l
# Ok: delete
find /thepath -type f ! -name '*.gz' -print0 | xargs -0 rm -vf
Oh, and to delete all empty left-over directories:
find /thepath -type d -empty -print0 | xargs -0 rmdir -v
I think
find /thepath -name "foo" ! -name "*.gz" -print0
should produce the correct list of filenames, but check before piping the output to your xargs command to perform the actual deletions.

Exclude a sub-directory using find

I have directory structure like this
data
|___
|
abc
|____incoming
def
|____incoming
|____processed
123
|___incoming
456
|___incoming
|___processed
There is an incoming sub-folder in all of the folders inside Data directory. I want to get all files from all the folders and sub-folders except the def/incoming and 456/incoming dirs.
I tried out with following command
find /home/feeds/data -type d \( -name 'def/incoming' -o -name '456/incoming' -o -name arkona \) -prune -o -name '*.*' -print
but it is not working as expected.
Ravi
This works:
find /home/feeds/data -type f -not -path "*def/incoming*" -not -path "*456/incoming*"
Explanation:
find /home/feeds/data: start finding recursively from specified path
-type f: find files only
-not -path "*def/incoming*": don't include anything with def/incoming as part of its path
-not -path "*456/incoming*": don't include anything with 456/incoming as part of its path
Just for the sake of documentation: You might have to dig deeper as there are many search'n'skip constellations (like I had to). It might turn out that prune is your friend while -not -path won't do what you expect.
So this is a valuable example of 15 find examples that exclude directories:
http://www.theunixschool.com/2012/07/find-command-15-examples-to-exclude.html
To link to the initial question, excluding finally worked for me like this:
find . -regex-type posix-extended -regex ".*def/incoming.*|.*456/incoming.*" -prune -o -print
Then, if you wish to find one file and still exclude pathes, just add | grep myFile.txt.
It may depend also on your find version. I see:
$ find -version
GNU find version 4.2.27
Features enabled: D_TYPE O_NOFOLLOW(enabled) LEAF_OPTIMISATION SELINUX
-name only matches the filename, not the whole path. You want to use -path instead, for the parts in which you are pruning the directories like def/incoming.
find $(INP_PATH} -type f -ls |grep -v "${INP_PATH}/.*/"
By following answer for How to exclude a directory in find . command:
find . \( -name ".git" -o -name "node_modules" \) -prune -o -print
This is what I did to exclude all the .git directories and passed it to -exec for greping something in the
find . -not -path '*/\.*' -type f -exec grep "pattern" [] \;
-not -path '*/\.*' will exclude all the hidden directories
-type f will only list type file and then you can pass that to -exec or whatever you want todo

Resources