bash on Linux, delete files with certain file extension - linux

I want to delete all files with a specific extension - ".fal", in a folder and its subfolders, except the one named "*Original.fal". The problem is that I want to delete other files that have the same extension:
*Original.fal.ds
*Original.fal.ds.erg
*Original.fal.ds.erg.neu
There are other ".fal"s that I want to delete as well, that don't have "Original" in them.
Names vary all the time, so I can't delete specific names. The *Original.fal doesn't vary.
I can only get up to here:
$find /disk_2/people/z183464/DOE-Wellen -name "*.fal" \! -name "*Original.fal" -type f -exec echo rm {} \;
It would be great if the command can delete only in the folder (and it's subfolders) where it has been called (executed)
When I run the code it gives me an error:
/disk_2/people/z183464/DOE-Wellen: is a directory

If you do not want find to dive too deep, you can restrict it with -maxdepth.

You can use a simple for loop for that. This command shows all the files you might want to delete. Change echo with rm to delete them.
cd /disk_2/people/z183464/DOE-Wellen && for I in `find . -name "*.fal" ! -name "*Original.fal"`; do echo $I; done
With "find ... | grep ..." you can use regex too, if you need more flexibility.

Related

Find all files with specific name and move it two levels up from its location

I want to find all files with specific name "stdout.1.0", move it two/three levels up from its location. While moving it two/three levels up, I also want to rename it to "testjob.out".
All "stdout.1.0" files are located six levels down from parent directory.
./dirXXXXXX/dirXXXXXX/dirXXXXXX/dirXXXXXX/dirXXXXXX/dirXXXXXX/stdout.1.0
I used:
find . -type f -name stdout.1.0
and it outputs:
./dir100000/dir110000/dir111000/dir111100/dir111110/dir111111/stdout.1.0
./dir100000/dir110000/dir112000/dir111100/dir111110/dir111111/stdout.1.0
./dir100000/dir110000/dir113000/dir111100/dir111110/dir111111/stdout.1.0
./dir200000/dir210000/dir211000/dir211100/dir211110/dir211111/stdout.1.0
./dir200000/dir210000/dir212000/dir211100/dir211110/dir211111/stdout.1.0
./dir200000/dir210000/dir213000/dir211100/dir211110/dir211111/stdout.1.0
./dir300000/dir310000/dir311000/dir311100/dir311110/dir311111/stdout.1.0
./dir300000/dir310000/dir312000/dir311100/dir311110/dir311111/stdout.1.0
./dir300000/dir310000/dir313000/dir311100/dir311110/dir311111/stdout.1.0
.
.
./dirXXX000/dirXXX000/dirXXX000/dirXXX100/dirXXX110/dirXXX111/stdout.1.0
The directories above is just representative of where the file is, but there are multiple "stdout.1.0" files starting three levels down from parent directory.
Here is a method in plain bash using globstar shell option , without using the find:
#!/bin/bash
shopt -s globstar
for file in **/stdout.1.0; do
echo mv "$file" "${file%/*/*/*}/testjob.out"
done
Drop the echo if output looks fine.
You already know how to find them:
find . -type f -name stdout.1.0
Now, you need to move them to a higher directory (..) and rename them:
find . -type f -name stdout.1.0 -execdir mv {} ../../testjob.out \;
I would advise you to copy them first and remove later (use cp instead of mv): if anything goes wrong, you can get back easily to the current situation.

Recursively delete files named `log` under multiple directories

I have a folder structure like the below:
feat1
feat2
feat3
Now within each folder we have another folder called builds.
Under builds we have numbered folders like 1, 2, etc.
Under each numbered folder we have files of the pattern *.log and then a particular file with the name log.
I need to run a command in the linux server / unix server to recursively delete only the file with the name log not the *.log for all these folders feat1, feat2 and feat3. How to do that?
The command you run depends on how careful you want to be about your search criteria and whether you need to search recursively.
Delete anything named log under feat*/builds/*/:
rm feat*/builds/*/log
Recursively find and delete anything named log anywhere under the current directory:
find . -name log -delete
Recursively find and delete anything named log, only under feat*:
find feat* -name log -delete
Recursively find and delete anything named log, only under feat*/builds/*/:
find feat*/builds/*/ -name log -delete
Recursively find and delete any file named log, only under feat*/builds/*/:
find feat*/builds/*/ -name log -type f -delete
Here is a quick and dirty solution using a for loop that should get the job done.
for f in `find feat* -name 'log'`; do rm "$f"; done;
for f in is saying we're going to do a for loop with f as the variable for each result.
find feat* -name 'log' searches through any directory starting with "feat" with * as a wildcard.
-name says we're looking for a file name of log.
do rm "$f" removes each result that was found.
Sometimes it is helpful to use echo before doing destructive commands this way. See below.
for f in `find feat* -name 'log'`; do echo "$f"; done;

Delete .DS_STORE files in current folder and all subfolders from command line on Mac

I understand I can use find . -name ".DS_Store" to find all the .DS_Store files in the current folder and all subfolders. But how could I delete them from command line simultaneously? I found it's really annoying to switch back and forth to all folders and delete it one by one.
find can do that. Just add -delete:
find . -name ".DS_Store" -delete
Extend it even further to also print their relative paths
find . -name ".DS_Store" -print -delete
For extra caution, you can exclude directories and filter only for files
find . -name ".DS_Store" -type f -delete
find . -name ".DS_Store" -print -delete
This will delete all the files named .DS_Store in the current path while also displaying their relative paths
Here is how to remove recursively the .DS_Store file
Open up Terminal
In the command line, go to the location of the folder where all files and folders are:
cd to/your/directory
Then finally, type in the below command:
find . -name '.DS_Store' -type f -delete
Press Enter
Cheers!!
You can also use extended globbing (**):
rm -v **/.DS_Store
in zsh, bash 4 and similar shells (if not enabled, activate by: shopt -s globstar).
The best way to do this cleanly is using:
find . -type f \( -name ".DS_Store" -o -name "._.DS_Store" \) -delete -print 2>&1 | grep -v "Permission denied"
This removes the files, hides "permission denied" errors (while keeping other errors), printing out a clean list of files removed.
All the answers above work but there is a bigger problem if one is using mac and still on mac. The described lines do delete all the DS_Store files but Finder recreates them immediately again because that is the default behaviour. You can read about how this all works here. To quote from there if you are on mac, you should remove them only if you really need:
If you don’t have a particular reason to delete these .DS_Store files (windows sharing might be a solid reason,) it’s best to leave them “as is.” There’s no performance benefit in deleting .DS_Store files. They are harmless files that don’t usually cause any problems. Remember that the .DS_Store file saves your personalized folder settings, such as your icon arrangement and column sortings. And that’s why you normally don’t want to delete them but rather HIDE them.
If you really do, there is one more way which was not mentioned here:
sudo find / -name “.DS_Store” -depth -exec rm {} \;
Make a new file with a text editor, copy and paste the following text into it, and save it with the ".sh" file extension, then open the file with Terminal. Make sure the text editor is actually saving the raw text and not saving the file as a Rich Text Format file or some other text file format with additional information in the file.
#!/bin/bash
echo -e "\nDrag a folder here and press the Enter or Return keys to delete all files whose names begin with a dot in its subfolders:\n"
read -p "" FOLDER
echo -e "\nThe following files will be deleted:\n"
find $FOLDER -name ".*"
echo -e "\nDelete these files? (y/n): "
read -p "" DECISION
while true
do
case $DECISION in
[yY]* ) find $FOLDER -name ".*" -delete
echo -e "\nThe files were deleted.\n"
break;;
[nN]* ) echo -e "\nAborting without file deletion.\n"
exit;;
* ) echo -e "\nAborting without file deletion.\n"
exit;;
esac
done
This wasn't exactly the question, but if you wanna actually zip the directory without them .DS_STORE files, this works a treat...
zip -r -X archive_name.zip folder_to_compress

Howto replace a file in several sub-folders

I've a series of directories containing a set of files. There is a new copy of this file which I would like to replace all instances with. How can do this with find command?
Latest file is in /var/www/html is called update_user.php
There are 125 directories with several other files including a copy of update_user.php. I want to replace these with the one in update_user.php excluding itself.
This should do the job:
find /path/to/old/files -type f -name update_user.php -exec cp /path/to/new/update_user.php {} \;
You should check if the new file is not inside /path/to/old and if so than first copy it outside and use that copy but.. it'll not harm if you don't - one cp will fail with are the same file error.
You can use
cp -v to see what it does
cp -u to update only when source file is newer
echo cp to perform dry run
I would suggest to check first if all dest. files are the same with:
find /path/to/old/files -type f -name update_user.php -exec md5sum {} \;|awk '{print $1}'|sort|uniq

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

Resources