544

I'm writing a makefile that will clean up some useless files at the end of the compilation. If a target has already been made, it will of course skip that target and the useless file may not be there. So if I do this:

rm lexer.ml interpparse.ml interpparse.mli

I may get errors because one of the files doesn't exist. Is there any way to tell rm to ignore these files?

In reading the man page, I see the following option:

 -f          Attempt to remove the files without prompting for confirma-
             tion, regardless of the file's permissions.  If the file does
             not exist, do not display a diagnostic message or modify the
             exit status to reflect an error.  The -f option overrides any
             previous -i options.

That sounds like almost what I want, but I'm not really sure about the permissions part. Is there a way to do this?

5
  • Did you try some rm in a sandbox? It looks like -f does exactly what you want, regardless of the globbing.
    – JMD
    Nov 27, 2009 at 17:02
  • 1
    If the permissions won't allow it, rm will with the -f option still try to delete it. It will fail. It won't tell you it failed. Useful if the filename is a variable or a glob.
    – LawrenceC
    Jun 13, 2012 at 1:24
  • 1
    just for completeness: there is rm --interactive=never which acts like rm -f except it does return an error exit status. see here for more details: unix.stackexchange.com/questions/72864/…
    – Lesmana
    Apr 8, 2019 at 7:11
  • Since you mentioned Makefile in the question, I think @robertLi's answer suits the best. Prepending with '-' is a make way of doing this; others dealing with Makefiles will likely recognise it.
    – akauppi
    Nov 27, 2019 at 13:34
  • Is the filesystem ZFS? On my raidz2 the weird file is a backup of `/var/spool/cups/d00019-001' I get Input/output error
    – Tomachi
    Sep 18, 2022 at 15:17

14 Answers 14

441

The -f option is definitely what you want to be using.

The confirmation about file permissions it refers to is this:

$ touch myfile    
$ chmod 400 myfile
$ rm myfile       
rm: remove write-protected regular empty file `myfile'?

So rm will warn you if you try to delete a file you don't have write permissions on. This is allowed if you have write permissions on the directory but is a little weird, which is why rm normally warns you about it.

2
  • 2
    Most, but not all systems will ask (I think). Some require -i. Nov 27, 2009 at 18:11
  • 3
    If you want the error message, but not the error exit code, see the answer by Giel Berkers. I use set -e in all my bash scripts so that the script exits after any command gives an error. I often want a script to tell me if rm gave an error, but continue anyway. continues.
    – cledoux
    Jun 6, 2016 at 4:05
225

Another solution is this one: https://stackoverflow.com/questions/11231937/bash-ignoring-error-for-a-particular-command

Just add an OR-statement after your command:

rm -rf my/dir || true

This way, when statement #1 fails (throws error), run statement #2, which is simply true.

5
  • 7
    It prints the error and continues the execution, which was desired for my case. Feb 29, 2016 at 14:28
  • 20
    Or just rm -rf my/dir ||: to be even more concise (: is short for true)
    – Godsmith
    Oct 4, 2016 at 14:55
  • The better solution in my opinion. It's easily visible what's happening and why the result code is ignored. I like it! Oct 3, 2017 at 14:13
  • This one is the only one that prevents script break when using set -e
    – dmikam
    Apr 8, 2020 at 16:50
  • 38
    ||: is a great way to confuse people who don't work with bash extensively but end up having to modify or comprehend your script at some point. rm --recursive --force my/dir || true should always be preferable now that we don't have massively slow and tedious 70s keyboards.
    – M-Pixel
    Feb 7, 2021 at 8:24
92

I'm way late to the party, but I use this all the time. In a makefile, add - to the beginning of a line to ignore the return value of that line. Like so:

-rm lexer.ml interpparse.ml interpparse.mli
6
  • 15
    This will still print error to the console though, which trains you to ignore errors in the make output, which is probably not what you want. rm -rf is a better option in my opinion.
    – Godsmith
    Oct 4, 2016 at 14:54
  • 1
    @Godsmith I'd rather ignore an error than forcing recursive delete. This could be very naughty. And +1 for the makefile specific syntax
    – Daishi
    Dec 6, 2017 at 15:06
  • If rm -rf could be "naughty", it means that you are using make outside a directory under version control. Why?
    – Godsmith
    Dec 8, 2017 at 7:27
  • Give a link to documentation, please. Could find description of this feature. Jan 30, 2018 at 16:50
  • 1
    I think this is superior. -f also skips interactive mode, skips readonly files etc. - this solution however does exactly what OP asked for.
    – phil294
    Mar 17, 2018 at 6:39
29

If you don't want to use the -f option, an alternative is:

rm filethatdoesntexist 2> /dev/null || true

This will just keep errors from being printed.

1
  • @ShaunMcDonald The answer has since been updated to add || true, so it is correct now. The answer also works for rmdir or any other command.
    – mbomb007
    Oct 30, 2023 at 20:12
8

If you find some way to glob the file names, rm won't complain if it can't find a match. So something like lexer.m* interpparse.*, etc. should work for you (be careful you're not deleting too much, of course). Also, -f is a perfectly reasonable way to go, as long as you're not hoping that file permissions will save you from deleting a file you didn't want to - if you don't want to delete it, don't put it in the list.

3
  • 1
    The globbing would be out of the question as there is a lexer.mll file that I don't want to delete. Thanks for showing why -f is reasonable. I suppose I tend to be overly careful after one too many misguided sudo rm -rf . Nov 27, 2009 at 16:53
  • Not even a more restrictive lexer.m? ...? That would catch lexer.ml and lexer.mz, but not lexer.mll or lexer.mla.
    – JMD
    Nov 27, 2009 at 16:58
  • 1
    @JMD: I suppose it depends on your shell and what pattern-matching support it offers for globbing. Nov 29, 2009 at 0:56
6

The -f option means that you will not be prompted if something is not as expected. It does not mean that permissions are not taken into account.

If you have not enough privileges to remove a file, it won't be removed.

BUT, if you have enough privileges to change privileges, you file will be removed. This is the case when you are the owner of a file with readonly permissions for owner (-r--------). As owner, you can chmod u+w, then remove it: rm -f will remove that file.

6

Maybe could help a line similar with:

touch fakefile.exe fakefile.o && rm *.o *.exe

I know that this is not very smart, but it does the job.

5

test to see if the file exists first, if it does, then pass it to rm. Then the errors from rm will be meaningful. -f or ignoring the error message is typically more encompassing than what a person wants. -f might do things you don't want done.

if [ -f lexer.ml ]; then
  rm lexer.ml
fi

add more test clauses if there are more files you want to be sure exist.

4

An alternative:

RmIfIsFile() {  for f in "$@"; do [ -f $f ] && rm $f; done; };  RmIfIsFile lexer.ml interpparse.ml interpparse.mli

Too bad Makefiles can't share shell function definitions across lines.

2
  • 1
    Have you tried to use \ (backslash) at the end of a row to let it continue on the next?
    – some
    Jul 31, 2012 at 19:35
  • 1
    @some: Yes, they can be spread across multiple lines, but to share them across recipes you have to put the definition in a make variable. Oct 1, 2012 at 13:56
3

Here's what I use in shell scripts. It hides the error message and error code.

rm doesnotexist 2> /dev/null || echo > /dev/null
1
  • how about rm doesnotexist 2&> /dev/null
    – user8162
    Feb 18, 2019 at 23:07
2

you can touch the files before you rm them. that would create them if they don't exist :-)

touch lexer.ml interpparse.ml interpparse.mli
rm lexer.ml interpparse.ml interpparse.mli
1

write rm -rf ppp>/dev/null 2>&1 you newer get error message Problem occurs, if error generate not to STDERR 2 but STDOUT 1... It's take place when command generate not error but warning. You need to set filter and remove this message. But this case is ordinary.

1

Simply supress the error message which is built-in function in rm command:

rm -f -- lexer.ml interpparse.ml interpparse.mli

It will remove the file if exists, otherwise it doesn't give any error message.

1

Simply check IF the directory/file already exists:

  • to remove a file

    file=path/to/the/file/to/copy && [ -f "${file}" ] && rm ${file} destination/path/here

  • to remove a directory

    dir=path/to/the/dir/to/copy && [ -d "${dir}" ] && rm -r ${dir} destination/path/here

NOTE:

the spaces before/after the square brackets are mandatory, not to break the above commands.

REFERENCES: https://linuxize.com/post/bash-check-if-file-exists/

1
  • 1
    Litle too much writing, try shorter: test -f path/to/the/file/to/copy && rm -fv $_
    – brablc
    Feb 16, 2022 at 8:35

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .