954,546 Members — Technology Publication meets Social Media
Username:
Password:
Lost login information?
Have something to say? Contribute New Article Reply to this Article

How do I? Edit Crontab using a Script?

I am a noob at shell scripting and have been reading up on this topic in random google searches.

The only way that I saw that worked was creating a tmpfile.

IE:

crontab -l > $tmpfile
edit $tmpfile
crontab $tmpfile
rm $tmpfile


I need a script that will comment out my watchdog line so I can upgrade mysql w/o any interference. I will also need to add at the end of this script to un-comment it.

Here is the line I would need commented. (no this is not all that is in my crontab)

*/5 * * * * /opt/watchdog/startwatchdog.sh


Any help would much be appreciated!!

egmik3
Light Poster
34 posts since Dec 2006
Reputation Points: 10
Solved Threads: 0
 

Hey There,

You should be able to do this with vi (assumming your EDITOR environment variable is set to vi).

First, check out this article on how to "really" insert control characters into your scripts (like ^H backspace rather than a ^ symbol followed by a capital H):

http://linuxshellaccount.blogspot.com/2007/10/how-to-really-represent-control.html

Then, you should be able to do something to the effect of this (I set up a user crontab file with some bogus information just to show you how this works (Note that the basic trick to passing actual control characters to a command or in a script is to type ctl-V followed by the, let's say, return key to generate the ^M, etc). Since you need to run two commands to edit, I put them in a subshell () so that they would both execute and feed through the pipe:

$ crontab -l # DO NOT EDIT THIS FILE - edit the master and reinstall. # (/tmp/crontab.Y8BaFrkEZY installed on Wed Jan 7 21:26:33 2009) # (Cron version V5.0 -- $Id: crontab.c,v 1.12 2004/01/23 18:56:42 vixie Exp $) 0 23 * * * /usr/bin/echo 0 23 * * * /usr/bin/watchdog 0 23 * * * /usr/bin/true 0 23 * * * /usr/bin/true

mgolvach@tlaum-pc1 ~ $ (echo ^[:g/watchdog/s/^/#/^[:wq!^M)|crontab -e Vim: Warning: Input is not from a terminal crontab: installing new crontab

mgolvach@tlaum-pc1 ~ $ crontab -l # DO NOT EDIT THIS FILE - edit the master and reinstall. # (/tmp/crontab.eQFF4ejmGJ installed on Wed Jan 7 21:26:47 2009) # (Cron version V5.0 -- $Id: crontab.c,v 1.12 2004/01/23 18:56:42 vixie Exp $) 0 23 * * * /usr/bin/echo #0 23 * * * /usr/bin/watchdog 0 23 * * * /usr/bin/true 0 23 * * * /usr/bin/true

mgolvach@tlaum-pc1 ~ $ (echo ^[:g/watchdog/s/^#//^[:wq!^M)|crontab -e Vim: Warning: Input is not from a terminal crontab: installing new crontab

mgolvach@tlaum-pc1 ~ $ crontab -l # DO NOT EDIT THIS FILE - edit the master and reinstall. # (/tmp/crontab.y4rIj2VKQz installed on Wed Jan 7 21:27:04 2009) # (Cron version V5.0 -- $Id: crontab.c,v 1.12 2004/01/23 18:56:42 vixie Exp $) 0 23 * * * /usr/bin/echo 0 23 * * * /usr/bin/watchdog 0 23 * * * /usr/bin/true 0 23 * * * /usr/bin/true


Best wishes,

If I can be of any extra help explaining, please let me know.

Mike

eggi
Posting Pro in Training
400 posts since Oct 2007
Reputation Points: 102
Solved Threads: 47
 

eggi,

I haven't had a chance to mess with this project today, but by looking at it. I got some questions:

# DO NOT EDIT THIS FILE - edit the master and reinstall.
# (/tmp/crontab.Y8BaFrkEZY installed on Wed Jan 7 21:26:33 2009)
# (Cron version V5.0 -- $Id: crontab.c,v 1.12 2004/01/23 18:56:42 vixie Exp $)


Why is this in it?

mgolvach@tlaum-pc1 ~


What is this an example of? Is this your pc's name?

Vim: Warning: Input is not from a terminal
crontab: installing new crontab


Why is this in it also?


So, a tmpfile is not needed for this script?


Sorry for all the questions, answer if you please.

Cheers!

egmik3
Light Poster
34 posts since Dec 2006
Reputation Points: 10
Solved Threads: 0
 

Forget my last post! The super noob powers in me came out.. I am playing around with the script you wrote. It seems like it will work. I am currently creating an atmosphere for this so I can test it.

I will get back to you.

Thanks again!

egmik3
Light Poster
34 posts since Dec 2006
Reputation Points: 10
Solved Threads: 0
 

Hey, Great - I hope it works out :)

Just to answer your questions:

mgolvach@tlaum-pc1 ~ is just my command prompt from my x86 linux box

The DO NOT COPY header is put in there by crontab. They recommend that you keep a copy somewhere else, modify that and then do "crontab thatfile" to update your crontab. This is strange, I've always thought because, if they didn't want you to edit your crontab file on the fly, why do they include the -e option to do just that? ;)

The input not from terminal error message is just generated since we're sending the vi commands through a pipe and not typing them in from the command line directly.

In summation - a tmpfile isn't need ;)

Best wishes,

Mike

eggi
Posting Pro in Training
400 posts since Oct 2007
Reputation Points: 102
Solved Threads: 47
 

>This is strange, I've always thought because, if they didn't want you to edit your crontab file on the fly, why do they include the -e option to do just that?

My understanding is that by using crontab -e, it checks for the validity of the job and proper format needed, while editing the file directly you are throwing the file as it is to cron, which undoubtedly could have repercussion in a negative way.

Furthermore by the use of the utility crontab, users can create jobs without the need of having access to root privileges or other users cron jobs.

Aia
Nearly a Posting Maven
2,392 posts since Dec 2006
Reputation Points: 2,224
Solved Threads: 218
 

Alright, I am trying to run a very simple script with just one of your lines.

Here's my script:

#!/bin/bash

crontab -l

 (echo ^[:g/watchdog/s/^/#/^[:wq!^M)|crontab -e


Here's what I get in my shell:

Continuity:/opt # ./watchdog_on_off
# DO NOT EDIT THIS FILE - edit the master and reinstall.
# (/tmp/crontab.XXXXg27puR installed on Fri Jan  9 17:31:02 2009)
# (Cron version V5.0 -- $Id: crontab.c,v 1.12 2004/01/23 18:56:42 vixie Exp $)
USER=root
JAVA_HOME=/usr/java/latest

0 9 * * * /etc/webmin/cron/tempdelete.pl
*/5 * * * * /opt/watchdog/startupWatchdog.sh
Vim: Warning: Input is not from a terminal
Vim: Error reading input, exiting...
Vim: preserving files...
Vim: Finished.
crontab: "/usr/bin/vi" exited with status 1
Continuity:/opt #
Broadcast message from root (Fri Jan  9 17:50:05 2009):

The system is going down for reboot NOW!


When it starts back up it does not have the watchdog line commented out.Can anyone explain this line of code?

(echo ^[:g/watchdog/s/^/#/^[:wq!^M)|crontab -e
egmik3
Light Poster
34 posts since Dec 2006
Reputation Points: 10
Solved Threads: 0
 

... Here is the line I would need commented. (no this is not all that is in my crontab)

*/5 * * * * /opt/watchdog/startwatchdog.sh

Any help would much be appreciated!!

The following should do the trick quite easily.

To comment out the line:

crontab -l >/tmp/crontab.a
sed -e 's=\(^.*/opt/watchdog/startwatchdog.sh$\)=#\1' /tmp/crontab.a | crontab
rm /tmp/crontab.a


To uncomment the line:

crontab -l >/tmp/crontab.a
sed -e 's=\(^#.*/opt/watchdog/startwatchdog.sh$\)=\1' /tmp/crontab.a | crontab
rm /tmp/crontab.a
Fest3er
Posting Whiz in Training
242 posts since Aug 2007
Reputation Points: 51
Solved Threads: 35
 

... Can anyone explain this line of code?

(echo ^[:g/watchdog/s/^/#/^[:wq!^M)|crontab -e

First, it assumes that the editor you are using to edit the crontab is vi(). If you've 'export EDITOR=vi' in the script, then this should be OK.

It is feeding vi() commands to the 'crontab -e' command's standard input. Were you to do this by hand, you would:

shell prompt> crontab -e
:g/watchdog/s/^/#/<ENTER>
:wq!<ENTER>
shell prompt>


:g is a global command; it searches for the first instance of watchdog, then executes the command that follows. In this case the following command is a substitution: change the beginning-of-line (^) to # (i.e., prepend a # to the line).

:wq! writes the file out (w) regardless of write privilege (!) and quits (q).
The 'character' between the two commands (^[) looks to be an escape (0x1b, 033, ESC) character. I think this should be a CR (see below).

If you are certain there won't be anything (anyone) else changing the crontab, it's far clearer to make a temp copy of the crontab, then use sed | crontab to change the line (as illustrated in my previous post).

Oh, the ^M is supposed to be a (0x0d, 015, CR). It might be clearer if it was

(echo -e ^[:g/watchdog/s/^/#/\r:wq!\r)|crontab -e


Vim() might properly interpret the ^M, but I usually don't trust it to; I use the actual ASCII control character by habit.

Fest3er
Posting Whiz in Training
242 posts since Aug 2007
Reputation Points: 51
Solved Threads: 35
 

Aia is correct about crontab -e. It does do checking, which is why I put that at the other end of the pipe :)

Basically the reason your script failed is that you need to actually put the control characters into your script, rather than just typing what they look like.

Here's that link again which explains how to do what I did in my command line (most notably entering real control-characters and not representations of them), although I owe a "thank you" to everyone else who's contributed to this thread with the same information and alternate options.

http://linuxshellaccount.blogspot.com/2007/10/how-to-really-represent-control.html

Again, my suggestion was only based on the fact that you didn't want to use a temp file. If you can live with creating and deleting a temp file, definitely do it that way. crontab should notify you of errors in your crontab file just like crontab -e would.

Best wishes,

Mike

eggi
Posting Pro in Training
400 posts since Oct 2007
Reputation Points: 102
Solved Threads: 47
 

wow, finally have time from Tech Support to start back on my script! I hope I can get this done sometime soon so I do not have to do all the upgrades by hand. I got some more questions for you pro's! :)

shell prompt> crontab -e
:g/watchdog/s/^/#/<ENTER>
:wq!<ENTER>
shell prompt>

Thank you for this!!! This explains a lot!

(echo -e ^[:g/watchdog/s/^/#/\r:wq!\r)|crontab -e

I was not able to get this to run. Every time I used echo I usually start the line with it not "(". Shouldn't I be able to paste this in the command prompt? When I do I get

bash: !\r: event not found

Also when I run it within the script I get this:

./mysql_upgrade: line 20: syntax error near unexpected token `echo'
./mysql_upgrade: line 20: `$ (echo -e ^[:g/watchdog/s/^/#/\r:wq!\r)|crontab -e'

Also I noticed if watchdog was already stopped ("#") then it adds another "#" to the line. My easy fix would be to run the line to remove "#" twice to make sure. Is this the best way?

Thanks for everything guys! This is actually getting fun!

egmik3
Light Poster
34 posts since Dec 2006
Reputation Points: 10
Solved Threads: 0
 
crontab -l >/tmp/crontab.a
sed -e 's=\(^.*/opt/watchdog/startwatchdog.sh$\)=#\1' /tmp/crontab.a | crontab
rm /tmp/crontab.a


I tried this as well.

Just trying to comment it out first off and here is what I get out of the command prompt:

# ./mysql_upgrade
sed: -e expression #1, char 44: unterminated `s' command
crontab: usage error: file name must be specified for replace
usage:  crontab [-u user] file
        crontab [-u user] [ -e | -l | -r ]
                (default operation is replace, per 1003.2)
        -e      (edit user's crontab)
        -l      (list user's crontab)
        -r      (delete user's crontab)


Any help on this one? If I can get either or to work that would be great!

Also using this method:

crontab -l >/tmp/crontab.a


It adds 3 extra lines to the top of crontab.a

# DO NOT EDIT THIS FILE - edit the master and reinstall.
# (/tmp/crontab.XXXXYMQNRs installed on Thu Mar  5 16:10:14 2009)
# (Cron version V5.0 -- $Id: crontab.c,v 1.12 2004/01/23 18:56:42 vixie Exp $)
USER=root
JAVA_HOME=/usr/java/latest

0 9 * * * /etc/webmin/cron/tempdelete.pl
*/5 * * * * /opt/watchdog/startupWatchdog.sh
egmik3
Light Poster
34 posts since Dec 2006
Reputation Points: 10
Solved Threads: 0
 

The following should do the trick quite easily.

To comment out the line:

crontab -l |sed -e 's=\(^.*/opt/watchdog/startwatchdog.sh$\)=#\1=' | crontab -

To uncomment the line:

crontab -l | sed -e 's=^#\(.*/opt/watchdog/startwatchdog.sh$\)=\1=' | crontab -

Forty lashes with a wet noodle for me for posting the wrong thing. The code above should work now; I've reduced it to a single line. This time I actually tested them. :$

It appears you don't have a choice when it comes to the first three lines of comments. Crontab() puts them in whether you like it or not. But you can safely ignore them; they're only comments.

Fest3er
Posting Whiz in Training
242 posts since Aug 2007
Reputation Points: 51
Solved Threads: 35
 

Forty lashes with a wet noodle for me for posting the wrong thing. The code above should work now; I've reduced it to a single line. This time I actually tested them. :$

It appears you don't have a choice when it comes to the first three lines of comments. Crontab() puts them in whether you like it or not. But you can safely ignore them; they're only comments.


I still was not able to get it to work. Are you using "Backspace" or "Delete" ? Delete is only way to get rid of the "#"

Here's my crontab:

USER=root
JAVA_HOME=/usr/java/latest

59 20 * * * /etc/webmin/cron/tempdelete.pl
#/5 * * * * /opt/watchdog/startupWatchdog.sh


Heres crontab after "uncomment" code:

# DO NOT EDIT THIS FILE - edit the master and reinstall.
# (- installed on Wed Mar 11 20:54:12 2009)
# (Cron version V5.0 -- $Id: crontab.c,v 1.12 2004/01/23 18:56:42 vixie Exp $)
# DO NOT EDIT THIS FILE - edit the master and reinstall.
# (/tmp/crontab.XXXXs7xGhE installed on Wed Mar 11 20:53:46 2009)
# (Cron version V5.0 -- $Id: crontab.c,v 1.12 2004/01/23 18:56:42 vixie Exp $)
USER=root
JAVA_HOME=/usr/java/latest

59 20 * * * /etc/webmin/cron/tempdelete.pl
#/5 * * * * /opt/watchdog/startupWatchdog.sh


Also if ran multiply times it adds more comments. This file could get messy.

# DO NOT EDIT THIS FILE - edit the master and reinstall.
# (- installed on Wed Mar 11 20:54:31 2009)
# (Cron version V5.0 -- $Id: crontab.c,v 1.12 2004/01/23 18:56:42 vixie Exp $)
# DO NOT EDIT THIS FILE - edit the master and reinstall.
# (- installed on Wed Mar 11 20:54:12 2009)
# (Cron version V5.0 -- $Id: crontab.c,v 1.12 2004/01/23 18:56:42 vixie Exp $)
# DO NOT EDIT THIS FILE - edit the master and reinstall.
# (/tmp/crontab.XXXXs7xGhE installed on Wed Mar 11 20:53:46 2009)
# (Cron version V5.0 -- $Id: crontab.c,v 1.12 2004/01/23 18:56:42 vixie Exp $)
USER=root
JAVA_HOME=/usr/java/latest

59 20 * * * /etc/webmin/cron/tempdelete.pl
#/5 * * * * /opt/watchdog/startupWatchdog.sh
egmik3
Light Poster
34 posts since Dec 2006
Reputation Points: 10
Solved Threads: 0
 

Of course it won't work now. You changed the watchdog line in crontab from

*/5 * * * */opt/watchdog/startwatchdog.sh


as you originally specified, to

/5 * * * * /opt/watchdog/startupWatchdog.sh

You will have toRestore the leading asterisk so that cron doesn't complain and so that the crontab is syntactically correct, and
change the code I provided to handle the other difference, or restore the original file name.

The one-line shell command I supplied does work. You just have to match the original conditions you specified.

Remember, Linux does not have a "Do What I Mean" interface; it has only a "Do What I Say" interface. You need to be explicit and correct when you tell Linux to do something. Using less caution can be catastrophic to the running system.

As to the leading comments in the file that replicate every time you edit the crontab, you should file a bug report with your linux distributor. This particular condition is known as 'non-idempotence'. 'Crontab -e' should strip out those leading comments before letting the user edit the file, unless their intent was to maintain a semi-absolute log of each time the crontab was editted.

Fest3er
Posting Whiz in Training
242 posts since Aug 2007
Reputation Points: 51
Solved Threads: 35
 

Of course it won't work now. You changed the watchdog line in crontab from

*/5 * * * */opt/watchdog/startwatchdog.sh

as you originally specified, to

/5 * * * * /opt/watchdog/startupWatchdog.sh

You will have to

  • Restore the leading asterisk so that cron doesn't complain and so that the crontab is syntactically correct, and
  • change the code I provided to handle the other difference, or restore the original file name.

The one-line shell command I supplied does work. You just have to match the original conditions you specified.

Remember, Linux does not have a "Do What I Mean" interface; it has only a "Do What I Say" interface. You need to be explicit and correct when you tell Linux to do something. Using less caution can be catastrophic to the running system.

As to the leading comments in the file that replicate every time you edit the crontab, you should file a bug report with your linux distributor. This particular condition is known as 'non-idempotence'. 'Crontab -e' should strip out those leading comments before letting the user edit the file, unless their intent was to maintain a semi-absolute log of each time the crontab was editted.


Thank you for all the help!

Do you think it would be possible to just run another command to delete the added 3 lines?

egmik3
Light Poster
34 posts since Dec 2006
Reputation Points: 10
Solved Threads: 0
 

Thank you for all the help!

Do you think it would be possible to just run another command to delete the added 3 lines?

This may be starting to get ugle and specific to Linux or Posix version of certain tools. The following seem to work:

# Comment out the entry
crontab -l | \
egrep  -m 3 -v "^# DO NOT EDIT THIS FILE|^# \(- installed on|^# \(Cron version --" | \
sed -e 's=\(^.*/opt/watchdog/startwatchdog.sh$\)=#\1=' | \
crontab -

# Uncomment the entry
crontab -l | \
egrep  -m 3 -v "^# DO NOT EDIT THIS FILE|^# \(- installed on|^# \(Cron version --" | \
sed -e 's=^#\(.*/opt/watchdog/startwatchdog.sh$\)=\1=' | \
crontab -


This should make the file idempotent: there should now only be the initial three comment lines in the crontab. If you want even those erased, you'll have to modify the crontab program.

Fest3er
Posting Whiz in Training
242 posts since Aug 2007
Reputation Points: 51
Solved Threads: 35
 

This basically runs the commands in sequence: ESC, :, grep for "watchdog" and substitute the beginning of the line with a #, ESC, wq!, RETURN
-Dan

danwoz
Newbie Poster
1 post since May 2010
Reputation Points: 10
Solved Threads: 0
 

First, it assumes that the editor you are using to edit the crontab is vi(). If you've 'export EDITOR=vi' in the script, then this should be OK.

It is feeding vi() commands to the 'crontab -e' command's standard input. Were you to do this by hand, you would:

shell prompt> crontab -e
:g/watchdog/s/^/#/<ENTER>
:wq!<ENTER>
shell prompt>

:g is a global command; it searches for the first instance of watchdog, then executes the command that follows. In this case the following command is a substitution: change the beginning-of-line (^) to # (i.e., prepend a # to the line).

:wq! writes the file out (w) regardless of write privilege (!) and quits (q). The 'character' between the two commands (^[) looks to be an escape (0x1b, 033, ESC) character. I think this should be a CR (see below).

If you are certain there won't be anything (anyone) else changing the crontab, it's far clearer to make a temp copy of the crontab, then use sed | crontab to change the line (as illustrated in my previous post).

Oh, the ^M is supposed to be a (0x0d, 015, CR). It might be clearer if it was

(echo -e ^[:g/watchdog/s/^/#/\r:wq!\r)|crontab -e
Vim() might properly interpret the ^M, but I usually don't trust it to; I use the actual ASCII control character by habit.

Yeah, way to go

Toni Vlaic

Tomaker
Newbie Poster
4 posts since May 2010
Reputation Points: 10
Solved Threads: 1
 

Will This work on AIX

fsh68
Newbie Poster
1 post since Jun 2010
Reputation Points: 10
Solved Threads: 0
 

This question has already been solved

Post: Markdown Syntax: Formatting Help
You