8

When I try to execute mail from inside a function in a bash script it creates something similar to a fork bomb. To clarify, this creates the issue:

#!/bin/bash

mail() {
    echo "Free of oxens" | mail -s "Do you want to play chicken with the void?" "example@example.org"
}

mail

exit 0

Sometimes you can just kill the command and it'll kill the child processes, but sometimes you'll have to killall -9.

It doesn't care whether the mail were sent or not. The fork bomb is created either way. And it doesn't seem as adding any check for the exit code, such as if ! [ "$?" = 0 ], helps.

But the script below works as intended, either it outputs an error or it sends the mail.

#!/bin/bash

echo "Free of oxens" | mail -s "Do you want to play chicken with the void?" "example@example.org"

exit 0

Why does this happen? And how would you go about checking the exit code of the mail command?

  • 10
    It is called recursion. – Jakuje Jan 20 '16 at 17:57
29

You're invoking the function mail from within the same function:

#!/bin/bash

mail() {
    # This actually calls the "mail" function
    # and not the "mail" executable
    echo "Free of oxens" | mail -s "Do you want to play chicken with the void?" "example@example.org"
}


mail

exit 0

This should work:

#!/bin/bash

mailfunc() {
    echo "Free of oxens" | mail -s "Do you want to play chicken with the void?" "example@example.org"
}

mailfunc

exit 0

Note that function name is no longer invoked from within the function itself.

  • 3
    Happens to the best of us, man. – Almo Jan 20 '16 at 20:55
15

Otherwise:

mail(){

    echo olly olly oxenfree | command mail -s 'and the rest' and@more
}

...should work fine.

  • 7
    Perhaps emphasising the command part, as for the layperson it is hard to notice that change along with the olly olly oxenfree and 'and the rest' and@more changes, especially with the syntax highlighting. – wizzwizz4 Jan 20 '16 at 17:22
  • 1
    @wizzwizz4 - I support this comment. – mikeserv Jan 20 '16 at 17:33
  • 1
    It is funny though... – wizzwizz4 Jan 20 '16 at 17:39
3

The most "traditional" solution in these cases is actually to call the command with full path:

mail() {
    echo "Free of oxens" | /usr/bin/mail -s "Do you want to play chicken with the void?" "example@example.org"
}

All other answers work, and are probably more portable, but I think that this is the most likely solution you'd find in scripts in the wild real world, so I'm including it for completeness.

  • 3
    Indeed I'm not used to mail being in /usr/bin. – Joshua Jan 20 '16 at 20:26
  • 3
    @Joshua, it seems to be there on OS X. In CentOS 6 it's /bin/mail. I think this proves the value of the command mail syntax. – Wildcard Jan 20 '16 at 20:49
  • Arch Linux also has this in /usr because their paradigm is to move all the binaries to the same directory, so /bin is just a symlink to /usr/bin. So yes... this isn't portable, but it's more commonly seen than command, somehow - especially in legacy boot scripts that were made specifically to each distribution, all the absolute paths were hardcoded (rc scripts in Slackware, for instance). – orion Jan 21 '16 at 12:34

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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