Hacker News new | past | comments | ask | show | jobs | submit login
Cronic - A cure for Cron's chronic email problem (habilis.net)
63 points by duck on May 25, 2012 | hide | past | favorite | 45 comments

In a dozen or so years of administrating many different Unix machines, I've never had cron email be a problem and I get a few (useful) emails from various cron scripts every day.

This interacts badly with many unix commands, which often send status info to standard out. Some commands have a quiet options, but that can turn off all error output too.

Maybe it's that I've mostly been administrating BSD machines, and so most of the tools follow old Unix guidelines like not printing anything unless it's necessary, echoing errors to stderr, using proper exit statuses, etc. (http://fmg-www.cs.ucla.edu/geoff/interfaces.html) I think it's a GNUism/Linuxism that commands are overly chatty, writing junk all over stdout (like author/license information - do we need to see this every single time?), and using ANSI colors by default.

Which tools are you talking about? The standard software suite is basically identical between the systems. And what differences there are lie in the implementations of the core stuff, whose behavior is specified by POSIX for the most part.

I'm sure there are exceptions somewhere. But in something you'd throw into a cron job? Frankly, that seems like a very weird snipe.

I'm guessing ls which colors; perhaps keychain (very colorful output).

I see less of the license stuff these days but no doubt there's a few around.

On Red Hat based systems, ls is an alias for ls --color=auto which means that colors are used only on terminals, not pipes or files.

And no one should ever be using ls in a shell script anyway. Shell globbing and find are the proper tools.

Debian has this as well. I do "unalias -a" whenever I log into an account I haven't configured to my liking yet (I want no ls coloring, but I do want a bash prompt in boldface).

I think it's an OSX-ism.

Most OSX devs I've seen treat their command-line utilities like their GUI utilities, with nice looking albeit chatty output.

These utilities then get released into the Linux world, where they often work without any modification.

Or it's just younger devs, who like to see something when they run their program.

Yes, exactly this. I know I'm guilty of wanting to see something cool happen. :)

I remember getting an angry email from someone because of this when I was back at uni, had just finishing installing a linux box at home, but hadn't finished configuring everything. I went to bed while it was busily running cron jobs throughout the remainder of the night and emailing the output to someone else who had the same username at my ISP as the local one I'd set up on the machine. I don't think he saw the funny side of it sadly.

You're bang on. Commands should do what you tell them and say nothing unless something unexpected occurred. (or, if you asked them to say something)

Cron isn't broken. It's chatty programs that are broken.

So you can scream at the darkness or light a candle. It doesn't matter which is broken if you can only fix one.

I don't quite think that its a "gnuism" to do that. They generally take a --color option which of course is off by default.

They did sometimes put the license everytime, a long time ago, but I don't see that anymore unless you ask the version or help.

GNU programs that show a license and copyright information at startup do so when used interactively, not when in batch mode. For example:

echo 1 + 2 | bc

That doesn't produce anything except "3", even with GNU bc.

I added a simplified version of chronic to moreutils a while back. http://joeyh.name/code/moreutils (also packaged in some major linux distros)

It's not just simplified, but more secure. Your version doesn't write to predictable filenames in /tmp like the original does.

moreutils is a nice package to have installed in any case. For example, sponge is very handy at times.

(Disclaimer: I wrote isutf8, which is included in moreutils.)

I don't like spurious cron emails either, that's why I put effort into writing decent scripts.

There are more "fixes" for cron than I can count. I interpret this more as a fundamental misunderstanding of unix utilities and standards.

Utilities should not print out anything that the user can safely ignore. If you want to print out more info, add a VERBOSE mode (-v or -vv ...).

Writing programs like this must be a rite of passage. About a year ago I wrote one (https://github.com/mlaiosa/cronwrap). One day when I googled "cronwrap" to try to find the github page, there was a gazillion hits of other programs that also did the same thing. I looked at a couple and I still like mine more - but I also have a moderate case of not-invented-here syndrome.

Since this is hackernews, can someone explain the rational behind putting the 2>&1 after the > ?

I know it works, but this reads to me: command > file.txt 2>&1 "write the output of command to file.txt and then map the error output to stdout"

It makes so much more sense to write: command 2>&1 > file.txt

There is clearly something in my brain that is confused about how redirection works.

&1 refers to file descriptor 1. a>&b calls dup2(2) with oldfd=b and newfd=a. So ordering matters. STDOUT starts out attached to fd=1, but if you dup something else to fd=1, the association "fd 1 is STDOUT" is forgotten.

And that's exactly what usually happens; we replace fd 1 with one open to /dev/null, and then when we say 2>&1, that means to replace fd 2 (stderr) with whatever's at fd 1 (now /dev/null). When you write "command 2>&1 >/dev/null" that means something else, it means "send fd 2's output to what's currently at fd 1 (stdout)", and then "send what's currently at fd 1 to /dev/null". In other words, the source of a redirection is "by reference", but the destination of a redirection is "by value". If that makes any sense...

Think of it as saying "take fd 2 (stderr) and send it to the same place fd 1 is going now" So:

  $ command >file.txt 2>&1
first redirects fd=1 to file.txt and then has fd=2 go the same place. Where:

  $ command 2>&1 >file.txt
first has fd=2 go the original place stdout was and then redirect fd=1 only to file.txt. Usually not what you want. If you really wanted file.txt to get only the stdout while simultaneously sending what used to be stderr to stdout I think you'd have to use another file descriptor like:

  $ command 3>&1 >file.txt 2>&3
That is, save the original stdout as fd=3, redirect stdout, then make stderr go the same place fd=3 is going.

I think this[1] is probably what you're looking for. If I'm understainding you correctly, the 2nd example will have mapped 2/stderr to &1 (stdout), before pointing stdout to the file, so you end up with both in the file.

[1] http://wiki.bash-hackers.org/syntax/redirection#multiple_red...

Siblings have already responded to this well, so I'll just add an example:

  $ ls x
  ls: cannot access x: No such file or directory
  $ ls x >/dev/null 2>&1
  $ ls x 2>&1 >/dev/null
  ls: cannot access x: No such file or directory
The first command shows us trying to list a non-existent file, raising an error. The second sends stderr to stdout before sending stdout to null, suppressing all output. The third sends the error to stdout; any output on stdout would have been suppressed (can you come up with a way to verify this?)

can you come up with a way to verify this?

   perl -E 'say q{STDOUT!}; say {*STDERR} q{STDERR!}'
(q{...} quoting to avoid ugliness of quotes inside quotes.)

Your second example puts stderr into the old stdout, then makes a new stdout go into the file. You have to redirect the files in the proper sequence to get the desired behavior. It is quirky if you don't expect it.

I have this problem, I only want to be emailed upon failure. However, the crontab of the account is shared by several different jobs run by different people, and I don't have control over that. Perhaps I could set the email in the crontab line?

* * * * * MAILTO=me@example.com blahscript.sh

You can set MAILTO by itself between the job lines in the crontab; e.g.:

    * */10 * * * script1
    5 * * * * script2
    * * * * * script3
Any output from script1 and 2 will be sent to user1 and any from script3 to user2.

Not all cron daemons. Vixie cron can do this, but Dillon's cron, which is a lightweight cron daemon with extra features, can't.

Thanks for the clarification.

    blahscript.sh | mail -s "Subject" me@example.com

That always sends an email, even if the body is empty.

mail -E

Wouldn't it be simpler to just only direct stdout to /dev/null and let cron capture stderr?

That's not too bad and too be honest I think I'd like to see it inside cron. So we'd just..

* * * * * blahscript.sh

and it'd do what cronic does without any extra. I know i know the "one tool one job", but i believe this job is really cron's job (word play unintended)

I use a wrapper similar to this. Sometimes you just need to call a script someone else wrote that you have no control over the output. I never want an email unless the script results in a non-zero rc.

There are many different cron implementations. Do none of them check exit status?

All of them.

cron sends a mail if: a) there's output (stdout or stderr) or b) the command exit code isn't 0.

So I really don't understand the post when it says "Now when your cron job fails, you will never know about it.".

Well, if you script fails and still returns 0, your script is broken. If you script outputs stuff when it's not supposed to, it can't run from cron.

Oh man. I was all excited reading the headline until I realized that you weren't talking about a cure for Crohn's.

One exists. Hookworm aka Helminthic therapy.

Unfortunately the FDA has ruled that this treatment would require approval. The approval process is expensive, and there is no way that anyone can recoup their expenses for doing so. Therefore this treatment will never be approved in the USA.

But I know someone who had severe Crohn's disease who went to Canada to receive a mail order of hookworm. Thanks to that he's been totally off drugs for over a year, and shows no signs of the disease.

I like how the web page switches to two-column layout if it has enough screen space.

now that's nice. i did not notice, as it depends on javascript. but very nice! something to copy i guess ;).

(that alone is worth the article. the "real" content is just misunderstanding of unix i'm afraid)

Three columns here.

Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | Legal | Apply to YC | Contact