Customized deleting files from a folder - linux

I have a folder where different files can be located. I would like to check if it contains other files than .gitkeep and delete them, keeping .gitkeep at once. How can I do this ? (I'm a newbie when it comes to bash)

As always, there are multiple ways to do this, I am just sharing what little I know of linux :
1)find <path-to-the-folder> -maxdepth 1 -type f ! -iname '\.gitkeep' -delete
maxdepth of 1 specifies to search only the current directory. If you remove maxdepth, it will recursively find all files other than '.gitkeep' in all directories under your path. You can increase maxdepth to however deep you want find to go into directories from your path.
'-type f' specifies that we are just looking for files . If you want to find directories as well (or links, other types ) then you can omit this option.
-iname '.gitkeep' specifies a case insensitive math for '.gitkeep', the '\' is used for escaping the '.', since in bash, '.' is a regular expression.
You can leave it to be -name instead of -iname for case sensitive match.
The '!' before -iname, is to do an inverse match, i.e to find all files that don't have the name '.gitkeep', if you remove the '!', then you will get all files that match '.gitkeep'.
finally, '-delete' will delete the files that match this specification.
If you want to see what all files will be deleted before executing -delete, you can remove that flag and it will show you all the files :
find <path-to-the-folder> -maxdepth 1 -type f ! -iname '\.gitkeep'
(you can also use -print at the end, which is just redundant)
2) for i in `ls -a | grep -v '\.gitkeep'` ; do rm -rf $i ; done
Not really recommended to do it this way, since rm -rf is always a bad idea (IMO). You can change that to rm -f (to ensure it just works on file and not directories).
To be on the safe side, it is recommended to do an echo of the file list first to see if you are ready to delete all the files shown :
for i in `ls -a | grep -v '\.gitkeep'` ; do echo $i ; done
This will iterate thru all the files that don't match '.gitkeep' and delete them one by one ... not the best way I suppose to delete files
3)rm -rf $(ls -a | grep -v '\.gitkeep')
Again, careful with rm -rf, instead of rm -rf above, you can again do an echo to find out the files that will get deleted
I am sure there are more ways, but just a glimpse of the array of possibilities :)
Good Luck,
Ash
================================================================
EDIT :
=> manpages are your friend when you are trying to learn something new, if you don't understand how a command works or what options it can take and do, always lookup man for details.
ex : man find
=> I understand that you are trying to learn something out of your comfort zone, which is always commendable, but stack overflow doesn't like people asking questions without researching.
If you did research, you are expected to mention it in your question, letting people know what you have done to find answers on your own.
A simple google search or a deep dive into stack overflow questions would have provided you with a similar or even a better answer to your question. So be careful :)
Forewarned is forearmed :)

You can use find:
find /path/to/folder -maxdepth 1 ! -name .gitkeep -delete

Related

How can i count the number of files with a specific octal code without them showing in shell

I tried using tree command but I didn't know how .(I wanted to use tree because I don't want the files to show up , just the number)
Let's say c is the code for permission
For example I want to know how many files are there with the permission 751
Use find with the -perm flag, which only matches files with the specified permission bits.
For example, if you have the octal in $c, then run
find . -perm $c
The usual find options apply—if you only want to find files at the current level without recursing into directories, run
find . -maxdepth 1 -perm $c
To find the number of matching files, make find print a dot for every file and use wc to count the number of dots. (wc -l will not work with more exotic filenames with newlines as #BenjaminW. has pointed out in the comments. Source of idea of using wc -c is this answer.)
find . -maxdepth 1 -perm $c -printf '.' | wc -c
This will show the number of files without showing the files themselves.
If you're using zsh as your shell, you can do it natively without any external programs:
setopt EXTENDED_GLOB # Just in case it's not already set
c=0751
files=( **/*(#qf$c) )
echo "${#files[#]} files found"
will count all files in the current working directory and subdirectories with those permissions (And gives you all the names in an array in case you want to do something with them later). Read more about zsh glob qualifiers in the documentation.

Bash for loop that removes files without suffixes from multiple directories

I have 5000 directories that need cleaning. I want to run a script that removes files without a suffix and keep those with any suffix. I know that all files without a suffix can be safely removed because these directories contain images of various types. I've tried this:
for i in $(ls -d */)
do
rm $i !(*.*)
done
I get a syntax error
syntax error near unexpected token `('
` rm $i !(*.*)'
I really don't want to repeat that process 5000 times. Any help would be greatly appreciated!
Please don't iterate over the output of ls. It is extremely risky, error-prone and strongly discouraged by the authors. Also, if you just want to find files and delete them, the find utility will do that a lot more efficiently.
The most basic version would be:
$ find . -mindepth 2 -type f ! -name "*.*" -delete
This is efficient because you won't start 5000 processes of rm (one for each directory). In fact, this is just one process. find will call unlink() to remove the file as it finds it.

Using Perl how can I clean up left over directories with no files?

There is a specific directory which is used as a temp/scratch directory by some program.
E.g. /a/b/c/work
Under work multiple hierarchical directories may exist e.g.
/a/b/c/work/
\d1/
\d1.1
\d2
\d2.2
What I want is to clean up this work directory as there are left over files that take space.
Essentially I need to delete all subdirectories under work that the leaf directory is empty.
So if d1.1 is empty but d2.2 has files then delete everything under d1 (including d1) but not d2.
What is the cleanest/standard way to do this in perl?
I thought to use a solution with backticks e.g. rm -rf etc but I thought there could be some better way than coding sequences of ls folowed by rm
Note: Just to be clear. I want a solution in Perl as this is not a one time thing and I dont want to do this manually each time
If you use find command this way you can achieve it.
find /path/to/dir -empty -type d -delete
Where,
-empty Only find empty files and make sure it is a regular file or a directory.
-type d Only match directories.
-delete Delete files.
Always put -delete option at the end of find command as 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.
To automate this in shell script follow below code:
path=`pwd`
find $path -empty -type d -delete
or you can give certain input as arguments of shell script like myShell.sh /path/to/mydir in that case the following code will be do the work,
$path=$1
find $path -empty -type d -delete
As for if you really want to go for perl you can find your answer as follows
use strict;
use warnings;
use File::Util;
my $path = '...';
my $fu = File::Util->new();
my #all_dirs = $fu->list_dir($path, '--recurse', '--dirs-only');
my #empty_dirs = grep { not $fu->list_dir($_) } #all_dirs;
also a short method
perl -MFile::Find -e"finddepth(sub{rmdir},'.')"
which is explained very good here.

Remove files for a lot of directories - Linux

How can I remove all .txt files present in several directories
Dir1 >
Dir11/123.txt
Dir12/456.txt
Dir13/test.txt
Dir14/manifest.txt
In my example I want to run the remove command from Dir1.
I know the linux command rm, but i don't know how can I make this works to my case.
PS.: I'm using ubuntu.
To do what you want recursively, find is the most used tool in this case. Combined with the -delete switch, you can do it with a single command (no need to use -exec (and forks) in find like other answers in this thread) :
find Dir1 -type f -name "*.txt" -delete
if you use bash4, you can do too :
( shopt -s globstar; rm Dir1/**/*.txt )
We're not going to enter sub directories so no need to use find; everything is at the same level. I think this is what you're looking for: rm */*.txt
Before you run this you can try echo */*.txt to see if the correct files are going to be removed.
Using find would be useful if you want to search subfolders of subfolders, etc.
There is no Dir1 in the current folder so don't do find Dir1 .... If you run the find from the prompt above this will work:
find . -type f -name "*.txt" -delete

Find in Linux combined with a search to return a particular line

I'm trying to return a particular line from files found from this search:
find . -name "database.php"
Each of these files contains a database name, next to a php variable like $dname=
I've been trying to use -exec to execute a grep search on this file with no success
-exec "grep {\}\ dbname"
Can anyone provide me with some understanding of how to accomplish this task?
I'm running CentOS 5, and there are about 100 database.php files stored in subdirectories on my server.
Thanks
Jason
You have the arguments to grep inverted, and you need them as separate arguments:
find . -name "database.php" -exec grep '$dbname' /dev/null {} +
The presence of /dev/null ensures that the file name(s) that match are listed as well as the lines that match.
I think this will do it. Not sure if you need to make any adjustments for CentOS.
find . -name "database.php" -exec grep dbname {} \;
I worked it out using xargs
find . -name "database.php" -print | xargs grep \'database\'\=\> > list_of_databases
Feel free to post a better way if you find one (or what some rep for a good answer)
I tend to habitually avoid find because I've never learned how to use it properly, so the way I'd accomplish your task would be:
grep dbname **/database.php
Edit: This command won't be viable in all cases because it can potentially generate a very long argument list, whereas find executes its command on found files one by one like xargs. And, as I noted in my comment, it's possibly not very portable. But it's damn short ;)

Resources