Actually this kind of too much to ask I think.

But I want to remove all files matching the extension ".sh"(current folder only) which I can do with below command:

find . -maxdepth 1 -type f -name '*.sh' -exec rm {} +

But still I want to keep file "cron.sh" in the current folder unaffected.

How can I achieve this in single command line ?

  • With extended globbing: rm -- !(cron).sh – steeldriver Oct 20 '16 at 12:41
  • @steeldriver damn! I was trying to figure that one out using rm !(cron.sh) and couldn't find a way for it to not delete non-sh files. Nice one! Please post it as an answer. – terdon Oct 20 '16 at 14:12
  • @terdon it is given in one of the answers in the dupe - I was in the process of writing it as an answer here when it got locked. – steeldriver Oct 20 '16 at 14:16

You can use -not:

find . -maxdepth 1 -type f -name '*.sh' -not -name cron.sh -delete

Also, GNU find has the -delete option which is simpler to use and than rm -rf.

Important: Always put -delete at the end. As explained 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.

Alternatively, you could use a shell loop (but don't, the find command above is far more efficient):

for f in *.sh; do [ "$f" = "cron.sh" ] || rm "$f"; done
  • Thank you, please keep both the answers. So I can use -name and -not -name in same line, any disadvantages with them ? – Vicky Dev Oct 20 '16 at 12:18
  • @VickyDev um, no. What kind of disadvantages? You can do very complicated things with find. You can string multiple conditions together (-not, -or, -and) and use \( and \) for more complex grouping. This is very simple and one line should be fine. – terdon Oct 20 '16 at 12:21
  • Maybe you could point out that find's command execution is "left to right" so when using -delete to make sure to put it at the end. People have suffered from this often enough. Oh, the terrible nightmares are haunting me to this day.... – FelixJN Oct 20 '16 at 12:21
  • I rarely the gnu one, but if you are going the gnu find way, can you add " +" after "-delete" to have it work on multiple files at once (with less forking)? or is it not possible with -delete? – Olivier Dulac Oct 20 '16 at 12:42
  • 1
    @OlivierDulac I just tested this by comparing the times of -delete, -exec rm {} \; and -exec rm {} + and the -delete was the fastest. I am assuming it calls unlink() directly and doesn't fork at all since it isn't calling any external commands. – terdon Oct 20 '16 at 14:07

An alternative, but slower way then the great find example by terdon is to use mv and rm commands chained with and operators.

mv cron.sh cron.sh.safe && rm *.sh && mv cron.sh.safe cron.sh

This will complain if you have any directories named something.sh, but will not delete them.

Not the answer you're looking for? Browse other questions tagged or ask your own question.