At is a system daemon that lets you run something at a time or date in the
future. It differs from cron in that it is designed for one-offs. You don't have to
edit a complex file as in crontab; you simply issue a command like
at now + 30 minutes.
It is perfect for things like reminders, which is what I use it for most of the time.
One of the things you want in a reminder is some sort of notification to alert you (obviously). Typically, a sound plays and a notice pops up to tell you about the reminder.
It is such a common use case that I wrote a simple shell script to do just that. It
aplay to play the sound and
zenity (you could use
xmessage) to pop up a simple text box.
However, ever since I set it up a couple of years ago, sound has never worked when I ran
at, which pretty much defeated the purpose of the thing.
The symptoms were a bunch of errors (in the email I get from
at's output) such as these:
ALSA lib confmisc.c:768:(parse_card) cannot find card '0' ALSA lib conf.c:4184:(_snd_config_evaluate) function snd_func_card_driver returned error: No such file or directory ALSA lib confmisc.c:392:(snd_func_concat) error evaluating strings ALSA lib conf.c:4184:(_snd_config_evaluate) function snd_func_concat returned error: No such file or directory ALSA lib confmisc.c:1251:(snd_func_refer) error evaluating name ALSA lib conf.c:4184:(_snd_config_evaluate) function snd_func_refer returned error: No such file or directory ALSA lib conf.c:4663:(snd_config_expand) Evaluate error: No such file or directory ALSA lib pcm.c:2212:(snd_pcm_open_noupdate) Unknown PCM default
I put these errors verbatim for google to index so anyone else with this problem can find it.
I checked all the permissions and ownerships and everything seemed ok. In the end, I gave up.
Today, with gritted teeth and girded loins(!), I got stuck into it. It works fine when run as root or through sudo. It must be something to do with permissions. Time to google.
Finally, a throwaway comment in a VectorLinux forum provided a clue. The user did not have
his name as a member of the
But, I am a member of the audio group, as the
groups command tells me:
In a moment of inspiration, I checked the contents of
odd, I don't appear as a member of audio. A bit more checking and it turns out I don't
appear as a member for a bunch of groups (video, cdrom, scanner), notwithstanding
anything that the
groups command might tell me. It is clear that the group
file (or perhaps gshadow) is out of sync with whatever database the
gpasswd to add myself to each of the missing groups. (I noticed this had the
side effect of also changing
/etc/gshadow, which previously had been empty.)
Success. My alert script now plays a sound and pops up a text box. Hooray.
To recap: something somewhere is broken. The symptoms were that me, the user, could
play a sound, but that
at (running as a command initiated by me) could not.
Both root and
at running from root could play a sound.
If I had to take a guess, I would say that the interactive shell permissions were ok,
at is checked against either
/etc/gshadow. How that would happen is something I shall investigate later.
I think I've figured it out, thanks to a little help at Linux Questions. Slackware automatically adds a console user to the groups defined in
at runs the command in a separate shell, I am guessing that
that shell is not defined as a login shell (which makes sense), so the user is not in
those groups when the command runs.
The answer is to do what I did and manually add the user to the groups, although, instead
gpasswd you can use the
vigr editor (which I did not
know about) as root to edit
One of the strangest design decisions in
at is that it is interactive. There is no way to specify on the command
line what you want to run. For example, sed lets you specify its commands on the
command line with the
-e switch, as in
sed -e 's/foo/bar/g'
file. At doesn't let you do that. It drops you into a shell in which you
type the commands you want. This means you can't use it in a script. As I said, it is
a strange design; I have never wanted to issue more than one command at a time (where a
shell makes sense), but have many, many times wanted to use
at within a
Of course, it is relatively trivial to work around with something like
"some_command" | at now + 2 days or
at now + 2 days <<<