rm command

I don’t see it in the man pages so I thought I’d ask.

Can rm (or other) be used such that I can do something like:

Delete all files that are not jpegs.

rm * not jpg

I guess that would be boolean delete operations: and, not, or.

find . -name * ! -name *.jpg -exec rm {} ; seems to be the command.

Please check it first without the -exec rm {} ; as I’m no find expert.
find . -name * ! -name *.jpg

Should find all files except for ones ending in .jpg

FeatherMonkey, your solution works, but mine is simpler:
rm *.jpg
At least it deletes al files ending on .jpg in the working directory.

If that is the same as Jpeg files I cannot say. If a file contents apply to the Jpeg rules has nothing to do with its name. Although I admit that it is customary to give those files names ending in .jpeg (or .jpg on OSs that have length restrictions).

And mooreted, there is of course nothing about this in the man page of rm. This file name expansion is done by the shell, which then calls rm with the range of names that were generated by the expansion.

hcvv think you maybe speed reading they want to delete all but *.jpg like you I presume .jpg

Maybe my command isn’t quite correct I know you’ve confirmed before whether my find is correct I thought ! was except in this instance.

So find all except *.jpg (An exclamation mark not pipe wondering whether it looks like a pipe now.)

I did check it with some on my system but I rarely use find and I’m only beginning to understand the syntax now.

I am sory, you are right!!!

But I still think a nice regular expression may solve this. I will not try one, because I completely spoiled my reputation.

In the spirit of experimentation and education… rsync is useful for many things, including your scenario of deleting all but .jpg files. man rsync or info rsync is useful… Anyways, here is an example to (re)transfer all included files but delete excluded files… I couldn’t find a switch that would make it ignore upper/lower case filenames, even so, to be safe, being specific as to what to include/exclude is usually good practice anyways…

> ls -1
> rsync -ai --delete-excluded --include=‘.jpg’ --include='.JPG’ --exclude=’***’ ./ ./
.d ./
*deleting test3.gif
*deleting test3.desktop
*deleting test2.txt
*deleting test2.exe
*deleting test2.GIF
*deleting test1.png
*deleting test1.gif
.f test1.jpg
.f test2.jpg
.f test3.JPG
.f test3.jpg
> ls -1


hehe you can show me the re way I would be interested still really, really struggle with re here.

I would of struggled for a few hrs even with a calc like here Regular Expressions I have it bookmarked for a reason :wink:

Oops, the spirits are catching us.

FeatherMonkey’s solution (when our working directory is the one we want to do this):
find . ! -name ‘.jpg’
for listing them and
find . ! -name '
.jpg’ -exec rm {} ;
to remove them (inclusive those found in sub-directories!!)
first the * and the *.jpg must be enclosed in quotes because else the shell willl expand them and in this case the *s are for **find **and not for the **shell (**so there was a little bit of truth in my first abortive lesson);
second the first expression is not needed, the second is enough.
I tested it (the listing only version).

And pikerhog shows to advantage that you can in Linux/Unix do everything in at least 10 different ways (of which at least 5 are acceptable as ‘nice’).

Let me first have a sleep over this. I will report back, even if I fail.

heh… in the spirit of Linux/Unix doing everything at least 10 different ways… I love perl.

This simple perl script, when named rmallexcept and chmod 755 rmallexcept, works too…


note: this is VERY crude and not precise. but just to experiment and get the mind thinking…

if ($ARGV[0]) {
$rmcommand = “rm -i”; # or remove flag -i to not ask for each removal.
$dirlist=ls -1 | grep -E "^[a-zA-Z0-9]"; # single column list of filenames in current dir starting with an alphanum

    foreach $dirlistfilename (split ("

", $dirlist)) {
# this if statement is finds everthing but user’s input, intended to delete
# if case should matter, remove the i below, between / and )
if ($dirlistfilename !~ /.$ARGV[0]$/i) {
#system(’$rmcommand $dirlistfilename’); #uncomment to really do deletion
print "Would have removed $dirlistfilename via: $rmcommand $dirlistfilename
"; #comment this line out after testing
} else {
print "Specify a file extension to exclude from deletion! ie, jpg

so like, if put into ~/bin it could be called from anywhere (usually)…

> cd tmp/
> ls -1
> ls -1
> rmallexcept JpG
Would have removed test1.gif via: rm -i test1.gif
Would have removed test1.png via: rm -i test1.png
Would have removed test2.GIF via: rm -i test2.GIF
Would have removed test2.exe via: rm -i test2.exe
Would have removed test2.txt via: rm -i test2.txt
Would have removed test3.desktop via: rm -i test3.desktop
Would have removed test3.gif via: rm -i test3.gif



find . ! -iname ‘*.jpg’ -print0 | xargs -0 rm

I leave it to you to exclude other file suffixes.

Back after a nice sleep and a fine run on sundaymorning :smiley:

Found the solution using the shell only (not calling other helpers like find, rc, perl, etc.). I will use **echo **instead of **rm **for obvious reasons:

echo *!.]!j]!p]!g]

Do we continue providing more solutions (we did not reach 10 until now)?

Also works::

ls | while read FN
do       $FN == *.jpg ]] || echo $FN

Who offers a PHP solution?

mooreted, are yo still with us? Did you already decide what to use? Or gave you up following us :confused:

Careful with filenames containing spaces.

I made a file with a space in it and it works, see the last file down here:

henk@boven:~> ls | while read FN
> do       $FN == *.jpg ]] || echo $FN
> done
spatie spatie

But I agree that when yyou want to program such actions in a script, you should test all those peculiarities.


I am not awake enough to think about all of that yet. :wink:

Thank you all for your solutions. I will have to try them on some test files and see which seems the most elegant for me.

I was thinking I could do:

mkdir temp
mv jpg temp
rm *

As well.

Solution #6 (or 7 or so).

May I correct a little bit?

mkdir temp
mv *.jpg temp/
rm *
cd temp
mv * ../
cd -
rmdir temp

Because yours would also move a file like README-about-these-jpg-files, mine only those ending in .jpg and mine moves the saved files back and removes the tempdir to clean everything up (not that you did not think about that yourself of course). The / at the end of the directories are not mandatory butI like to make clear it is about a directory.

Well yeah. I figured the last bit was understood. :slight_smile:

You have to move the files back to their original dir.

My solution is not very granular though. When I have time I will have to look at some of the other solutions for better control when lots of different files are mixed and need to be sorted out easily.

hcvv schrieb:
> Back after a nice sleep and a fine run on sundaymorning :smiley:
> Found the solution using the shell only (not calling other helpers like
> find, rc, perl, etc.). I will use *echo *instead of *rm *for obvious
> reasons:
> Code:
> --------------------
> echo *!.]!j]!p]!g]
> --------------------

Close, but no cigar:

ts@xenon:~/kernel> mkdir /tmp/tessst
ts@xenon:~/kernel> cd !$
cd /tmp/tessst
ts@xenon:/tmp/tessst> touch a.jpg b.kpg c.pkg d.pgk
ts@xenon:/tmp/tessst> ls
a.jpg b.kpg c.pkg d.pgk
ts@xenon:/tmp/tessst> echo *!.]!j]!p]!g]
ts@xenon:/tmp/tessst> touch e.jpgk
ts@xenon:/tmp/tessst> echo *!.]!j]!p]!g]