1

In the following example I would like foo to be deleted in case of error. Unfortunately it doesn't work.

foo:
    perl -e 'die()' > $@ || [rm $@ -a true]

What is it wrong?

nowox
  • 25,978
  • 39
  • 143
  • 293
  • Have you tried `perl -e 'die()' > $@ || rm $@`? – Leon May 31 '17 at 09:03
  • Yes, but it doesn't propagates `$?` of the first process. – nowox May 31 '17 at 09:04
  • 1
    Then `perl -e 'die()' > $@ || { rm $@; exit 1; }` (unless you need to propagate the exit status of the first process exactly) – Leon May 31 '17 at 09:06
  • The special variable `$@` should be quoted (eg. `perl -e 'die()' > "$@" || rm "$@"`. – l'L'l May 31 '17 at 09:14
  • 1
    @Leon `perl -e 'die()' > $@ || { rm $@; false;}` should work also and avoids exiting too fast – Nahuel Fouilleul May 31 '17 at 09:43
  • Work fine for me if I modify your command to `ls /tmp1 > $@ || rm $@`. Is it possible that the return value of `perl -e 'die()' > $@` always be true? – CWLiu May 31 '17 at 09:49
  • This might be helpful: https://stackoverflow.com/questions/15569228/can-a-makefile-execute-code-only-when-an-error-has-occurred – RTLinuxSW May 31 '17 at 12:48

2 Answers2

4

GNU make can do that for you.

Special Built-in Target Names:

.DELETE_ON_ERROR

If .DELETE_ON_ERROR is mentioned as a target anywhere in the makefile, then make will delete the target of a rule if it has changed and its recipe exits with a nonzero exit status, just as it does when it receives a signal.


It is a general problem that creating a file is a non-atomic operation. And not always you can delete an incomplete or corrupted file on termination, for example, when the program is killed with SIGKILL or by the OOM-killer. In other words, all solutions involving removing the file are prone to failures.

The robust generic solution is:

  1. Create the file with a temporary filename.
  2. Once the file is complete and have correct permissions, rename it to the final name. Renaming a file is an atomic operations in UNIX, as long as the file stays in the same filesystem.

E.g.:

foo:
    perl -e 'die()' > $@~
    mv --force $@~ $@
Community
  • 1
  • 1
Maxim Egorushkin
  • 131,725
  • 17
  • 180
  • 271
0

This works for me…

foo: 
    @perl -e 'die()' > $@ || { echo "removing $@ because exit code was $${?}"; rm $@; }

Output

Died at -e line 1.
removing foo because exit code was 255
Shammel Lee
  • 4,092
  • 1
  • 17
  • 20