recursively delete all files except some especific types - bash

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.

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 delete all folders except some

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

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

how to ignore directories but not the files in them in bash script with find

I want to run a find command but only find the files in directories, not the directories or subdirectories themselves. Also acceptable would be to find the directories but grep them out or something similar, still listing the files in those directories. As of right now, to find all files changed in the last day in the working directory, and grep'ing out DS_Store and replacing spaces with underscores:
find . -mtime -1 -type f -print | grep -v '\.DS_Store' | awk '{gsub(/ /,"_")}; 1'
Any help would be appreciated!
If you have GNU find:
find . -mtime -1 ! -name '.DS_Store' -type f -printf '%f\n'
will print only the basename of the file.
For other versions of find:
find . -mtime -1 ! -name '.DS_Store' -type f -exec basename {} \;
you could then do:
find -name index.html -exec sh -c 'basename "$1" | tr " " _' _ {} \;

shell script to traverse files recursively

I need some assistance in creating a shell script to run a specific command (any) on each file in a folder, as well as recursively dive into sub-directories.
I'm not sure how to start.
a point in the right direction would suffice. Thank you.
To apply a command (say, echo) to all files below the current path, use
find . -type f -exec echo "{}" \;
for directories, use -type d
You should be looking at the find command.
For example, to change permissions all JPEG files under your /tmp directory:
find /tmp -name '*.jpg' -exec chmod 777 {} ';'
Although, if there are a lot of files, you can combine it with xargs to batch them up, something like:
find /tmp -name '*.jpg' | xargs chmod 777
And, on implementations of find and xargs that support null-separation:
find /tmp -name '*.jpg' -print0 | xargs -0 chmod 777
Bash 4.0
#!/bin/bash
shopt -s globstar
for file in **/*.txt
do
echo "do something with $file"
done
To recursively list all files
find . -name '*'
And lets say for example you want to 'grep' on each file then -
find . -type f -name 'pattern' -print0 | xargs -0 grep 'searchtext'
Within a bash script, you can go through the results from "find" command this way:
for F in `find . -type f`
do
# command that uses $F
done

Resources