So to remove all files ending with .lnx, the cmd would be rm *.lnx, right?
If I want to remove all files that do NOT end with [.lnx], what command should I use?
Is there such a thing?
You can use this:
$ rm !(*.lnx)
!(pattern-list)
Matches anything except one of the given patterns.
A pattern-list is a list of one or more patterns separated by a ‘|’.
find . -depth 1 -type f -not -name '*.lnx' -delete
find all files (-type f) in the current directory (-depth 1) which do not match the filename (-not -name '*.lnx'), and delete them (-delete)
As always, test this first. Run it without the -delete to see all the files that match.
ls | grep -v '\.lnx$' | xargs rm
Related
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.
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 {} \;
I want to remove all previous versions of Tableau Reader.app from applications apart from the latest one. I want to do this through command line. The problem that I am having is I want to remove all files containing tableau reader except for the file tableau reader 2019.2.
I have tried multiple ways but they aren't working. I am not very experienced with this. Any help is appreciated. The script below: Checks if the Application is running and if not goes about deleting the different versions(bit I need help on)
#!/bin/bash
shopt -s extglob
process="$4"
processrunning=$( ps axc | grep "${process}" )
if [ "$processrunning" != "" ] ; then
echo "$process IS running, do nothing"
echo "error: script failed"
exit 1
else
echo "$process is not running and will remove the old versions"
find $HOME/Applications/ -type f -not -name 'Tableau Reader 2019.2.app' | grep "tableau reader" | xargs rm
#rm -r $HOME/Applications/Tableau Reader?*.app![$HOME/Applications/"Tableau Reader 2019.2.app"]
#find. -type f !( -name 'Tableau Reader 2019.2.app') -exec rm -f "Tableau Reader"*.app {} +
fi
try
ls "tableau reader"* | sort | head -n -1 | xargs -d '\n' rm
You can try this:
find $HOME/Applications -type f -not -name 'Tableau Reader 2019.2.app' | grep "Tableau Reader" | xargs -I {} rm {}
The scripts finds all the files except with the name Tableau Reader 2019.2.app and from that using grep all files containing Tableau Reader are separated and then deletes it.
This is achievable with the find command only, but lets test it before it deletes something:
find "$HOME/Applications/" -maxdepth 1 -type f -name 'Tableau Reader*.app' -not -name 'Tableau Reader 2019.2.app'
See if it returns the list of the files you want to delete only:
The list of files should look like this, with your home directory instead of /tmp:
/tmp/Applications/Tableau Reader 10.5.app
/tmp/Applications/Tableau Reader 2012.app
/tmp/Applications/Tableau Reader 10.3.app
/tmp/Applications/Tableau Reader 1.app
Lets see the options used to drive find:
find: the command to find files
"$HOME/Applications/": the directory to start the search
-maxdepth 1: stay in the directory, do not go into sub-directories
-type f: find regular files
-name 'Tableau Reader*.app': find files with names matching this pattern
-not -name 'Tableau Reader 2019.2.app' and not matching this other pattern
Now if you are satisfied with the list and are sure that you want to delete these files; find can do it for you if you add it the -delete option like this:
find "$HOME/Applications/" -maxdepth 1 -type f -name 'Tableau Reader*.app' -not -name 'Tableau Reader 2019.2.app' -delete
How about something like
rm -f $(find . -name "tableau reader*" -type f -exec ls -t {} \; | head -n +2)
Essentialy, run a subshell (as can be seen between $( and ) to obtain what to remove. Within that subshell, use find in the current directory only (.) with result type of file (f) exec an ls in time modified order using the -t flag. Then pipe to head starting at the 2nd result (-n +2) (which ensures your latest file is excluded from the rm command.
Note - you have to be careful with ls though as you'll get strange results if filenames contain some special characters, but for your use-case it looks like it should be fine.
What I do with these tasks is copy some test files to a new directory to get my expression perfect before scripting it. Make sure you use cp -a to preserve the file dates though.
I have directory called test which has sub folders in the date range like 01,02,...31. This all sub folders contain .bz2 files in it. I need to search all the files with .bz2 extension using find command but excluding particular range of directories. I know about find . -name ".bz2" -not -path "./01/*", but writing -not -path "./01/*" would be so pathetic if I would want to skip 10 directories. So how would I skip 01..19 subdirectories in my find command ?
You can use wildcards in the pattern for the option -not -path:
find ./ -type f -name "*.bz2" -not -path "./0*/*" -not -path "./1*/*
this will exclude all directories starting with 0 or 1. Or even better:
find ./ -type f -name "*.bz2" -not -path "./[01]*/*"
Firstly, you can help find by using -prune rather than -not -path - that will avoid even looking inside the relevant directories.
To your main point - you can build a wildcard for your example (numeric 01 to 19):
find . -path './0[1-9]' -prune -o -path './1[0-9]' -prune -o -print
If your range is less convenient (e.g. 05 to 25) you might want to build the range into a bash variable, then interpolate that into the find command:
a=("-path ./"{05..25}" -prune -o")
find . ${a[*]} -print -prune
(you might want to echo "${a[*]}" or printf '%s\n' ${a[*]} to see how it's working)
For me, I found the find command as a standalone tool somehow cumbersome. Therefore, I always end up using a combination of find just for the recursive file search and grep to make the actual exculsion/inclusion stuff. Finally I hand over the results to a third command which will perform the actions, like rm to remove files for example.
My generic command would look something like this:
find [root-path] | grep (-v)? -E "cond1|cond2|...|condN" | [action-performing-tool]
root-path is where to start the search recursively
add -v option is used to invert the matching results.
cond1 - condN, the conditions for the matching. When -v is involed then this are the conditions to not match.
the action-performing-tool does the actual work
For example you want to remove all files not matching some conditions in the current directory:
find . -not -name "\." | grep -v -E "cond1|cond2|cond3|...|condN" | xargs rm -rf
As you can see, we are searching in the current directory indicated by the dot as root-path: then we want to invert the matching results, because we want all files not matching our conditions: and finally we pass all files found to rm in order to delete them: I add -rf to recursive/force delete all files. I used the find command with -not -name "." to exclude the current directory indicated normally by dot.
For the actuall question: Assume we have a directory using .git and .metadata directory and we want to exclude them in our search:
find . -not -name "\." | grep -v -E ".git|.metadata" | [action-performing-tool]
Hope that helps!
If you wan to exclude child directory under parent directory then this might be useful:
E.g.- You have parent directory "ParentDir" and it has two child directories "Child1, Child2". You wan to read files from "Chiled2" only and skip "Child1". Then this will help.
find ./ParentDir ! -path "./ParentDir/Child1*" -name *.<extention>
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 :)