How do I add/remove cron jobs by script?











up vote
4
down vote

favorite
2












I'm going to make a bash script that is executed at boot and runs periodically.



I want it user-configurable, so that a user can add a cron job 0 * * * * my_script by running my_script add 0 * * * *, list jobs by my_script list, and remove by my_script remove job_number where the job number is listed in the output of my_script list command.



If I could manage crontab files separately, this would be easily achieved.
However, It seems crontab is only one file per a user (If not, please let me know). Directly dealing with that crontab file is a bad solution, of course.



So what is the proper way to handle the cron jobs? Or, is there a better way to handle periodically running scripts?



Conditions:




  1. Any user should be able to run it, whether privileged or not.

  2. No dependencies.


Additional question:



Since I couldn't find any proper way to manage periodically running scripts, I thought what I might be doing wrong. In the sense of software design, is it not practical to implement the interface to manage the software's scheduled tasks? Should I leave all schedule managements to users?










share|improve this question




























    up vote
    4
    down vote

    favorite
    2












    I'm going to make a bash script that is executed at boot and runs periodically.



    I want it user-configurable, so that a user can add a cron job 0 * * * * my_script by running my_script add 0 * * * *, list jobs by my_script list, and remove by my_script remove job_number where the job number is listed in the output of my_script list command.



    If I could manage crontab files separately, this would be easily achieved.
    However, It seems crontab is only one file per a user (If not, please let me know). Directly dealing with that crontab file is a bad solution, of course.



    So what is the proper way to handle the cron jobs? Or, is there a better way to handle periodically running scripts?



    Conditions:




    1. Any user should be able to run it, whether privileged or not.

    2. No dependencies.


    Additional question:



    Since I couldn't find any proper way to manage periodically running scripts, I thought what I might be doing wrong. In the sense of software design, is it not practical to implement the interface to manage the software's scheduled tasks? Should I leave all schedule managements to users?










    share|improve this question


























      up vote
      4
      down vote

      favorite
      2









      up vote
      4
      down vote

      favorite
      2






      2





      I'm going to make a bash script that is executed at boot and runs periodically.



      I want it user-configurable, so that a user can add a cron job 0 * * * * my_script by running my_script add 0 * * * *, list jobs by my_script list, and remove by my_script remove job_number where the job number is listed in the output of my_script list command.



      If I could manage crontab files separately, this would be easily achieved.
      However, It seems crontab is only one file per a user (If not, please let me know). Directly dealing with that crontab file is a bad solution, of course.



      So what is the proper way to handle the cron jobs? Or, is there a better way to handle periodically running scripts?



      Conditions:




      1. Any user should be able to run it, whether privileged or not.

      2. No dependencies.


      Additional question:



      Since I couldn't find any proper way to manage periodically running scripts, I thought what I might be doing wrong. In the sense of software design, is it not practical to implement the interface to manage the software's scheduled tasks? Should I leave all schedule managements to users?










      share|improve this question















      I'm going to make a bash script that is executed at boot and runs periodically.



      I want it user-configurable, so that a user can add a cron job 0 * * * * my_script by running my_script add 0 * * * *, list jobs by my_script list, and remove by my_script remove job_number where the job number is listed in the output of my_script list command.



      If I could manage crontab files separately, this would be easily achieved.
      However, It seems crontab is only one file per a user (If not, please let me know). Directly dealing with that crontab file is a bad solution, of course.



      So what is the proper way to handle the cron jobs? Or, is there a better way to handle periodically running scripts?



      Conditions:




      1. Any user should be able to run it, whether privileged or not.

      2. No dependencies.


      Additional question:



      Since I couldn't find any proper way to manage periodically running scripts, I thought what I might be doing wrong. In the sense of software design, is it not practical to implement the interface to manage the software's scheduled tasks? Should I leave all schedule managements to users?







      shell-script cron






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited May 6 '17 at 14:01









      Jeff Schaller

      37.9k1053123




      37.9k1053123










      asked May 6 '17 at 13:06









      queued

      2313




      2313






















          4 Answers
          4






          active

          oldest

          votes

















          up vote
          6
          down vote



          accepted










          Using cron is the correct way to schedule periodic running of tasks on most Unix systems. Using a personal crontab is the most convenient way for a user to schedule their own tasks. System tasks may be scheduled by root (not using the script below!) in the system crontab, which usually has an ever so slightly different format (an extra user field).



          Here's a simple script for you. Any user may use this to manage their own personal crontab.




          • It doesn't do any type of validation of its input except that it will complain if you give it too few arguments. It is therefore completely possible to add improperly formatted crontab entries.


          • The remove sub-command takes a line number and will remove what's on that line in the crontab, regardless of what that is. The number is passed, unsanitized, directly to sed.


          • The crontab entry, when you add one, has to be quoted. This affects how you must handle quotes inside the crontab entry itself.


          • It uses crontab.tmp as a file name to store a temporary file in the current directory, regardless of whether that file already exists or not (it will be removed).



          Most of those things should be relatively easy for you to fix.



          #!/bin/sh

          usage () {
          cat <<USAGE_END
          Usage:
          $0 add "job-spec"
          $0 list
          $0 remove "job-spec-lineno"
          USAGE_END
          }

          if [ -z "$1" ]; then
          usage >&2
          exit 1
          fi

          case "$1" in
          add)
          if [ -z "$2" ]; then
          usage >&2
          exit 1
          fi

          crontab -l >crontab.tmp
          printf '%sn' "$2" >>crontab.tmp
          crontab crontab.tmp && rm -f crontab.tmp
          ;;
          list)
          crontab -l | cat -n
          ;;
          remove)
          if [ -z "$2" ]; then
          usage >&2
          exit 1
          fi

          crontab -l | sed -e "$2d" >crontab.tmp
          crontab crontab.tmp && rm -f crontab.tmp
          ;;
          *)
          usage >&2
          exit 1
          ;;
          esac


          To use:



          $ ./script
          Usage:
          ./script add "job-spec"
          ./script list
          ./script remove "job-spec-lineno"

          $ ./script list
          1 */15 * * * * /bin/date >>"$HOME"/.fetchmail.log
          2 @hourly /usr/bin/newsyslog -r -f "$HOME/.newsyslog.conf"
          3 @reboot /usr/local/bin/fetchmail

          $ ./script add "0 15 * * * echo 'hello world!'"

          $ ./script list
          1 */15 * * * * /bin/date >>"$HOME"/.fetchmail.log
          2 @hourly /usr/bin/newsyslog -r -f "$HOME/.newsyslog.conf"
          3 @reboot /usr/local/bin/fetchmail
          4 0 15 * * * echo 'hello world!'

          $ ./script remove 4

          $ ./script list
          1 */15 * * * * /bin/date >>"$HOME"/.fetchmail.log
          2 @hourly /usr/bin/newsyslog -r -f "$HOME/.newsyslog.conf"
          3 @reboot /usr/local/bin/fetchmail





          share|improve this answer























          • Surely this would work, but I'm not asking how to add jobs at the last line and/or pick ones from all cron jobs and remove them. This may possibly collide with the other softwares (if they handle cron jobs poorly), and the users who deals with crontab frequently will end up with an ugly crontab file. I expected, for example, a folder per user which cron reads all the crontab files inside it and runs, so that I can make a separate crontab file for my script.
            – queued
            May 6 '17 at 16:18










          • A nice example: GNOME's startup application works this way! It reads all scripts from ~/.config/autostart/. However, I found that there are so many things from Linux that share this kind of "philosophy" of crontab. I'm so confused now. Thanks for the script anyway. Maybe I'm going to use it.
            – queued
            May 6 '17 at 16:20










          • @queued cron manages the tabs in exactly the way you describe (only one file per user though, by design). Have a look in /var/cron/tabs (it may be a different folder on your system). This is not to be modified through other means than by the crontab command though, so anything you build will have to use that. You could obviously also have a system where you have multiple crontabs per user, but you would need to concatenate these to have them activated by cron.
            – Kusalananda
            May 6 '17 at 16:24












          • My point is: I don't get the design that allows only one file per user. Is it intended, by some acceptable reasons?
            – queued
            May 6 '17 at 16:44






          • 1




            Now I got the point. I misinterpreted the program cron as the only way to run programs periodically, though it actually was just one of the programs that does the thing with a simple interface. I think I should make another program that periodically runs programs, or simply make a folder and make a cron job to run-parts it as you mentioned.
            – queued
            May 6 '17 at 17:32


















          up vote
          1
          down vote













          Your current cron implementation probably supports /etc/cron.d, where jobs have an additional "run as" user specified after the regular time fields and before the command. So, just adjust your interface to create files in that directory like regular cron entries with the username (perhaps extracted from the loginuid) prepended after the fifth field. Then you can do one job per file. :)



          Look at man 5 crontab
          https://linux.die.net/man/5/crontab



          Note that the main problem with this is that a user who can edit files in that directory could create a file which runs as root. So, you probably want a wrapper script run via sudo which will validate the input and force the calculated username into the generated file. And then got need to make sure you're doing things securely within the script, like not trusting $PATH, etc.



          PS, in a shell script: getent passwd $(</proc/self/loginuid)



          Honestly, if you're making users know the cron time format, a few extra seconds to teach them to use crontab -e (and set $EDITOR if vi is scary) isn't terribly difficult.






          share|improve this answer






























            up vote
            0
            down vote













            If you want a cron entry:



            0 * * * * my_script


            then I recommend you think of a separate name for your cron management function, like, "cron_mgmt", whose first argument is a SWITCH in a CASE statement:



            cron_mgmt () {

            case $1 in
            add ) ... ;;
            list ) ...;;
            remove ) ...
            help ) ...
            * ) echo "You need help. Here it is"
            cron_mgmt help
            ;;
            esac
            }





            share|improve this answer






























              up vote
              0
              down vote













              Rather than roll your own interface, keep it simple. To install a cron job with a certain schedule, place it in a certain directory. To remove it, remove it from the directory. You don't need to provide users with any tools to do that, just tell them which directory to put their job in.



              This is how most Linux distributions manage system cron jobs that can be installed by individual packages. Debian, Fedora, Arch Linux and others ship a tool called run-parts whose job is to run the scripts in a particular directory one by one. The different implementations of run-parts have different rules on exactly which file names are acceptable for scripts. If you don't want to depend on this, you can roll your own:



              for x in /path/to/daily-jobs/*; do
              if [ -x "$x" ]; then
              case "${x##*/}" in
              *[!-0-9A-Z_a-z]*) :;; # skip file names containing "weird" characters
              *) "$x";;
              esac
              fi
              done


              If you want to allow users to specify their own schedule, then this approach won't work. You need to rebuild the crontab file each time a new job is submitted. This can be done, but is complicated to set up reliably. However, if users can specify their own schedule, then there's little reason to add another interface on top of crontab -e, or a GUI that calls crontab -e under the hood.






              share|improve this answer





















                Your Answer








                StackExchange.ready(function() {
                var channelOptions = {
                tags: "".split(" "),
                id: "106"
                };
                initTagRenderer("".split(" "), "".split(" "), channelOptions);

                StackExchange.using("externalEditor", function() {
                // Have to fire editor after snippets, if snippets enabled
                if (StackExchange.settings.snippets.snippetsEnabled) {
                StackExchange.using("snippets", function() {
                createEditor();
                });
                }
                else {
                createEditor();
                }
                });

                function createEditor() {
                StackExchange.prepareEditor({
                heartbeatType: 'answer',
                convertImagesToLinks: false,
                noModals: true,
                showLowRepImageUploadWarning: true,
                reputationToPostImages: null,
                bindNavPrevention: true,
                postfix: "",
                imageUploader: {
                brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
                contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
                allowUrls: true
                },
                onDemand: true,
                discardSelector: ".discard-answer"
                ,immediatelyShowMarkdownHelp:true
                });


                }
                });














                draft saved

                draft discarded


















                StackExchange.ready(
                function () {
                StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f363376%2fhow-do-i-add-remove-cron-jobs-by-script%23new-answer', 'question_page');
                }
                );

                Post as a guest















                Required, but never shown

























                4 Answers
                4






                active

                oldest

                votes








                4 Answers
                4






                active

                oldest

                votes









                active

                oldest

                votes






                active

                oldest

                votes








                up vote
                6
                down vote



                accepted










                Using cron is the correct way to schedule periodic running of tasks on most Unix systems. Using a personal crontab is the most convenient way for a user to schedule their own tasks. System tasks may be scheduled by root (not using the script below!) in the system crontab, which usually has an ever so slightly different format (an extra user field).



                Here's a simple script for you. Any user may use this to manage their own personal crontab.




                • It doesn't do any type of validation of its input except that it will complain if you give it too few arguments. It is therefore completely possible to add improperly formatted crontab entries.


                • The remove sub-command takes a line number and will remove what's on that line in the crontab, regardless of what that is. The number is passed, unsanitized, directly to sed.


                • The crontab entry, when you add one, has to be quoted. This affects how you must handle quotes inside the crontab entry itself.


                • It uses crontab.tmp as a file name to store a temporary file in the current directory, regardless of whether that file already exists or not (it will be removed).



                Most of those things should be relatively easy for you to fix.



                #!/bin/sh

                usage () {
                cat <<USAGE_END
                Usage:
                $0 add "job-spec"
                $0 list
                $0 remove "job-spec-lineno"
                USAGE_END
                }

                if [ -z "$1" ]; then
                usage >&2
                exit 1
                fi

                case "$1" in
                add)
                if [ -z "$2" ]; then
                usage >&2
                exit 1
                fi

                crontab -l >crontab.tmp
                printf '%sn' "$2" >>crontab.tmp
                crontab crontab.tmp && rm -f crontab.tmp
                ;;
                list)
                crontab -l | cat -n
                ;;
                remove)
                if [ -z "$2" ]; then
                usage >&2
                exit 1
                fi

                crontab -l | sed -e "$2d" >crontab.tmp
                crontab crontab.tmp && rm -f crontab.tmp
                ;;
                *)
                usage >&2
                exit 1
                ;;
                esac


                To use:



                $ ./script
                Usage:
                ./script add "job-spec"
                ./script list
                ./script remove "job-spec-lineno"

                $ ./script list
                1 */15 * * * * /bin/date >>"$HOME"/.fetchmail.log
                2 @hourly /usr/bin/newsyslog -r -f "$HOME/.newsyslog.conf"
                3 @reboot /usr/local/bin/fetchmail

                $ ./script add "0 15 * * * echo 'hello world!'"

                $ ./script list
                1 */15 * * * * /bin/date >>"$HOME"/.fetchmail.log
                2 @hourly /usr/bin/newsyslog -r -f "$HOME/.newsyslog.conf"
                3 @reboot /usr/local/bin/fetchmail
                4 0 15 * * * echo 'hello world!'

                $ ./script remove 4

                $ ./script list
                1 */15 * * * * /bin/date >>"$HOME"/.fetchmail.log
                2 @hourly /usr/bin/newsyslog -r -f "$HOME/.newsyslog.conf"
                3 @reboot /usr/local/bin/fetchmail





                share|improve this answer























                • Surely this would work, but I'm not asking how to add jobs at the last line and/or pick ones from all cron jobs and remove them. This may possibly collide with the other softwares (if they handle cron jobs poorly), and the users who deals with crontab frequently will end up with an ugly crontab file. I expected, for example, a folder per user which cron reads all the crontab files inside it and runs, so that I can make a separate crontab file for my script.
                  – queued
                  May 6 '17 at 16:18










                • A nice example: GNOME's startup application works this way! It reads all scripts from ~/.config/autostart/. However, I found that there are so many things from Linux that share this kind of "philosophy" of crontab. I'm so confused now. Thanks for the script anyway. Maybe I'm going to use it.
                  – queued
                  May 6 '17 at 16:20










                • @queued cron manages the tabs in exactly the way you describe (only one file per user though, by design). Have a look in /var/cron/tabs (it may be a different folder on your system). This is not to be modified through other means than by the crontab command though, so anything you build will have to use that. You could obviously also have a system where you have multiple crontabs per user, but you would need to concatenate these to have them activated by cron.
                  – Kusalananda
                  May 6 '17 at 16:24












                • My point is: I don't get the design that allows only one file per user. Is it intended, by some acceptable reasons?
                  – queued
                  May 6 '17 at 16:44






                • 1




                  Now I got the point. I misinterpreted the program cron as the only way to run programs periodically, though it actually was just one of the programs that does the thing with a simple interface. I think I should make another program that periodically runs programs, or simply make a folder and make a cron job to run-parts it as you mentioned.
                  – queued
                  May 6 '17 at 17:32















                up vote
                6
                down vote



                accepted










                Using cron is the correct way to schedule periodic running of tasks on most Unix systems. Using a personal crontab is the most convenient way for a user to schedule their own tasks. System tasks may be scheduled by root (not using the script below!) in the system crontab, which usually has an ever so slightly different format (an extra user field).



                Here's a simple script for you. Any user may use this to manage their own personal crontab.




                • It doesn't do any type of validation of its input except that it will complain if you give it too few arguments. It is therefore completely possible to add improperly formatted crontab entries.


                • The remove sub-command takes a line number and will remove what's on that line in the crontab, regardless of what that is. The number is passed, unsanitized, directly to sed.


                • The crontab entry, when you add one, has to be quoted. This affects how you must handle quotes inside the crontab entry itself.


                • It uses crontab.tmp as a file name to store a temporary file in the current directory, regardless of whether that file already exists or not (it will be removed).



                Most of those things should be relatively easy for you to fix.



                #!/bin/sh

                usage () {
                cat <<USAGE_END
                Usage:
                $0 add "job-spec"
                $0 list
                $0 remove "job-spec-lineno"
                USAGE_END
                }

                if [ -z "$1" ]; then
                usage >&2
                exit 1
                fi

                case "$1" in
                add)
                if [ -z "$2" ]; then
                usage >&2
                exit 1
                fi

                crontab -l >crontab.tmp
                printf '%sn' "$2" >>crontab.tmp
                crontab crontab.tmp && rm -f crontab.tmp
                ;;
                list)
                crontab -l | cat -n
                ;;
                remove)
                if [ -z "$2" ]; then
                usage >&2
                exit 1
                fi

                crontab -l | sed -e "$2d" >crontab.tmp
                crontab crontab.tmp && rm -f crontab.tmp
                ;;
                *)
                usage >&2
                exit 1
                ;;
                esac


                To use:



                $ ./script
                Usage:
                ./script add "job-spec"
                ./script list
                ./script remove "job-spec-lineno"

                $ ./script list
                1 */15 * * * * /bin/date >>"$HOME"/.fetchmail.log
                2 @hourly /usr/bin/newsyslog -r -f "$HOME/.newsyslog.conf"
                3 @reboot /usr/local/bin/fetchmail

                $ ./script add "0 15 * * * echo 'hello world!'"

                $ ./script list
                1 */15 * * * * /bin/date >>"$HOME"/.fetchmail.log
                2 @hourly /usr/bin/newsyslog -r -f "$HOME/.newsyslog.conf"
                3 @reboot /usr/local/bin/fetchmail
                4 0 15 * * * echo 'hello world!'

                $ ./script remove 4

                $ ./script list
                1 */15 * * * * /bin/date >>"$HOME"/.fetchmail.log
                2 @hourly /usr/bin/newsyslog -r -f "$HOME/.newsyslog.conf"
                3 @reboot /usr/local/bin/fetchmail





                share|improve this answer























                • Surely this would work, but I'm not asking how to add jobs at the last line and/or pick ones from all cron jobs and remove them. This may possibly collide with the other softwares (if they handle cron jobs poorly), and the users who deals with crontab frequently will end up with an ugly crontab file. I expected, for example, a folder per user which cron reads all the crontab files inside it and runs, so that I can make a separate crontab file for my script.
                  – queued
                  May 6 '17 at 16:18










                • A nice example: GNOME's startup application works this way! It reads all scripts from ~/.config/autostart/. However, I found that there are so many things from Linux that share this kind of "philosophy" of crontab. I'm so confused now. Thanks for the script anyway. Maybe I'm going to use it.
                  – queued
                  May 6 '17 at 16:20










                • @queued cron manages the tabs in exactly the way you describe (only one file per user though, by design). Have a look in /var/cron/tabs (it may be a different folder on your system). This is not to be modified through other means than by the crontab command though, so anything you build will have to use that. You could obviously also have a system where you have multiple crontabs per user, but you would need to concatenate these to have them activated by cron.
                  – Kusalananda
                  May 6 '17 at 16:24












                • My point is: I don't get the design that allows only one file per user. Is it intended, by some acceptable reasons?
                  – queued
                  May 6 '17 at 16:44






                • 1




                  Now I got the point. I misinterpreted the program cron as the only way to run programs periodically, though it actually was just one of the programs that does the thing with a simple interface. I think I should make another program that periodically runs programs, or simply make a folder and make a cron job to run-parts it as you mentioned.
                  – queued
                  May 6 '17 at 17:32













                up vote
                6
                down vote



                accepted







                up vote
                6
                down vote



                accepted






                Using cron is the correct way to schedule periodic running of tasks on most Unix systems. Using a personal crontab is the most convenient way for a user to schedule their own tasks. System tasks may be scheduled by root (not using the script below!) in the system crontab, which usually has an ever so slightly different format (an extra user field).



                Here's a simple script for you. Any user may use this to manage their own personal crontab.




                • It doesn't do any type of validation of its input except that it will complain if you give it too few arguments. It is therefore completely possible to add improperly formatted crontab entries.


                • The remove sub-command takes a line number and will remove what's on that line in the crontab, regardless of what that is. The number is passed, unsanitized, directly to sed.


                • The crontab entry, when you add one, has to be quoted. This affects how you must handle quotes inside the crontab entry itself.


                • It uses crontab.tmp as a file name to store a temporary file in the current directory, regardless of whether that file already exists or not (it will be removed).



                Most of those things should be relatively easy for you to fix.



                #!/bin/sh

                usage () {
                cat <<USAGE_END
                Usage:
                $0 add "job-spec"
                $0 list
                $0 remove "job-spec-lineno"
                USAGE_END
                }

                if [ -z "$1" ]; then
                usage >&2
                exit 1
                fi

                case "$1" in
                add)
                if [ -z "$2" ]; then
                usage >&2
                exit 1
                fi

                crontab -l >crontab.tmp
                printf '%sn' "$2" >>crontab.tmp
                crontab crontab.tmp && rm -f crontab.tmp
                ;;
                list)
                crontab -l | cat -n
                ;;
                remove)
                if [ -z "$2" ]; then
                usage >&2
                exit 1
                fi

                crontab -l | sed -e "$2d" >crontab.tmp
                crontab crontab.tmp && rm -f crontab.tmp
                ;;
                *)
                usage >&2
                exit 1
                ;;
                esac


                To use:



                $ ./script
                Usage:
                ./script add "job-spec"
                ./script list
                ./script remove "job-spec-lineno"

                $ ./script list
                1 */15 * * * * /bin/date >>"$HOME"/.fetchmail.log
                2 @hourly /usr/bin/newsyslog -r -f "$HOME/.newsyslog.conf"
                3 @reboot /usr/local/bin/fetchmail

                $ ./script add "0 15 * * * echo 'hello world!'"

                $ ./script list
                1 */15 * * * * /bin/date >>"$HOME"/.fetchmail.log
                2 @hourly /usr/bin/newsyslog -r -f "$HOME/.newsyslog.conf"
                3 @reboot /usr/local/bin/fetchmail
                4 0 15 * * * echo 'hello world!'

                $ ./script remove 4

                $ ./script list
                1 */15 * * * * /bin/date >>"$HOME"/.fetchmail.log
                2 @hourly /usr/bin/newsyslog -r -f "$HOME/.newsyslog.conf"
                3 @reboot /usr/local/bin/fetchmail





                share|improve this answer














                Using cron is the correct way to schedule periodic running of tasks on most Unix systems. Using a personal crontab is the most convenient way for a user to schedule their own tasks. System tasks may be scheduled by root (not using the script below!) in the system crontab, which usually has an ever so slightly different format (an extra user field).



                Here's a simple script for you. Any user may use this to manage their own personal crontab.




                • It doesn't do any type of validation of its input except that it will complain if you give it too few arguments. It is therefore completely possible to add improperly formatted crontab entries.


                • The remove sub-command takes a line number and will remove what's on that line in the crontab, regardless of what that is. The number is passed, unsanitized, directly to sed.


                • The crontab entry, when you add one, has to be quoted. This affects how you must handle quotes inside the crontab entry itself.


                • It uses crontab.tmp as a file name to store a temporary file in the current directory, regardless of whether that file already exists or not (it will be removed).



                Most of those things should be relatively easy for you to fix.



                #!/bin/sh

                usage () {
                cat <<USAGE_END
                Usage:
                $0 add "job-spec"
                $0 list
                $0 remove "job-spec-lineno"
                USAGE_END
                }

                if [ -z "$1" ]; then
                usage >&2
                exit 1
                fi

                case "$1" in
                add)
                if [ -z "$2" ]; then
                usage >&2
                exit 1
                fi

                crontab -l >crontab.tmp
                printf '%sn' "$2" >>crontab.tmp
                crontab crontab.tmp && rm -f crontab.tmp
                ;;
                list)
                crontab -l | cat -n
                ;;
                remove)
                if [ -z "$2" ]; then
                usage >&2
                exit 1
                fi

                crontab -l | sed -e "$2d" >crontab.tmp
                crontab crontab.tmp && rm -f crontab.tmp
                ;;
                *)
                usage >&2
                exit 1
                ;;
                esac


                To use:



                $ ./script
                Usage:
                ./script add "job-spec"
                ./script list
                ./script remove "job-spec-lineno"

                $ ./script list
                1 */15 * * * * /bin/date >>"$HOME"/.fetchmail.log
                2 @hourly /usr/bin/newsyslog -r -f "$HOME/.newsyslog.conf"
                3 @reboot /usr/local/bin/fetchmail

                $ ./script add "0 15 * * * echo 'hello world!'"

                $ ./script list
                1 */15 * * * * /bin/date >>"$HOME"/.fetchmail.log
                2 @hourly /usr/bin/newsyslog -r -f "$HOME/.newsyslog.conf"
                3 @reboot /usr/local/bin/fetchmail
                4 0 15 * * * echo 'hello world!'

                $ ./script remove 4

                $ ./script list
                1 */15 * * * * /bin/date >>"$HOME"/.fetchmail.log
                2 @hourly /usr/bin/newsyslog -r -f "$HOME/.newsyslog.conf"
                3 @reboot /usr/local/bin/fetchmail






                share|improve this answer














                share|improve this answer



                share|improve this answer








                edited yesterday

























                answered May 6 '17 at 15:03









                Kusalananda

                120k16225369




                120k16225369












                • Surely this would work, but I'm not asking how to add jobs at the last line and/or pick ones from all cron jobs and remove them. This may possibly collide with the other softwares (if they handle cron jobs poorly), and the users who deals with crontab frequently will end up with an ugly crontab file. I expected, for example, a folder per user which cron reads all the crontab files inside it and runs, so that I can make a separate crontab file for my script.
                  – queued
                  May 6 '17 at 16:18










                • A nice example: GNOME's startup application works this way! It reads all scripts from ~/.config/autostart/. However, I found that there are so many things from Linux that share this kind of "philosophy" of crontab. I'm so confused now. Thanks for the script anyway. Maybe I'm going to use it.
                  – queued
                  May 6 '17 at 16:20










                • @queued cron manages the tabs in exactly the way you describe (only one file per user though, by design). Have a look in /var/cron/tabs (it may be a different folder on your system). This is not to be modified through other means than by the crontab command though, so anything you build will have to use that. You could obviously also have a system where you have multiple crontabs per user, but you would need to concatenate these to have them activated by cron.
                  – Kusalananda
                  May 6 '17 at 16:24












                • My point is: I don't get the design that allows only one file per user. Is it intended, by some acceptable reasons?
                  – queued
                  May 6 '17 at 16:44






                • 1




                  Now I got the point. I misinterpreted the program cron as the only way to run programs periodically, though it actually was just one of the programs that does the thing with a simple interface. I think I should make another program that periodically runs programs, or simply make a folder and make a cron job to run-parts it as you mentioned.
                  – queued
                  May 6 '17 at 17:32


















                • Surely this would work, but I'm not asking how to add jobs at the last line and/or pick ones from all cron jobs and remove them. This may possibly collide with the other softwares (if they handle cron jobs poorly), and the users who deals with crontab frequently will end up with an ugly crontab file. I expected, for example, a folder per user which cron reads all the crontab files inside it and runs, so that I can make a separate crontab file for my script.
                  – queued
                  May 6 '17 at 16:18










                • A nice example: GNOME's startup application works this way! It reads all scripts from ~/.config/autostart/. However, I found that there are so many things from Linux that share this kind of "philosophy" of crontab. I'm so confused now. Thanks for the script anyway. Maybe I'm going to use it.
                  – queued
                  May 6 '17 at 16:20










                • @queued cron manages the tabs in exactly the way you describe (only one file per user though, by design). Have a look in /var/cron/tabs (it may be a different folder on your system). This is not to be modified through other means than by the crontab command though, so anything you build will have to use that. You could obviously also have a system where you have multiple crontabs per user, but you would need to concatenate these to have them activated by cron.
                  – Kusalananda
                  May 6 '17 at 16:24












                • My point is: I don't get the design that allows only one file per user. Is it intended, by some acceptable reasons?
                  – queued
                  May 6 '17 at 16:44






                • 1




                  Now I got the point. I misinterpreted the program cron as the only way to run programs periodically, though it actually was just one of the programs that does the thing with a simple interface. I think I should make another program that periodically runs programs, or simply make a folder and make a cron job to run-parts it as you mentioned.
                  – queued
                  May 6 '17 at 17:32
















                Surely this would work, but I'm not asking how to add jobs at the last line and/or pick ones from all cron jobs and remove them. This may possibly collide with the other softwares (if they handle cron jobs poorly), and the users who deals with crontab frequently will end up with an ugly crontab file. I expected, for example, a folder per user which cron reads all the crontab files inside it and runs, so that I can make a separate crontab file for my script.
                – queued
                May 6 '17 at 16:18




                Surely this would work, but I'm not asking how to add jobs at the last line and/or pick ones from all cron jobs and remove them. This may possibly collide with the other softwares (if they handle cron jobs poorly), and the users who deals with crontab frequently will end up with an ugly crontab file. I expected, for example, a folder per user which cron reads all the crontab files inside it and runs, so that I can make a separate crontab file for my script.
                – queued
                May 6 '17 at 16:18












                A nice example: GNOME's startup application works this way! It reads all scripts from ~/.config/autostart/. However, I found that there are so many things from Linux that share this kind of "philosophy" of crontab. I'm so confused now. Thanks for the script anyway. Maybe I'm going to use it.
                – queued
                May 6 '17 at 16:20




                A nice example: GNOME's startup application works this way! It reads all scripts from ~/.config/autostart/. However, I found that there are so many things from Linux that share this kind of "philosophy" of crontab. I'm so confused now. Thanks for the script anyway. Maybe I'm going to use it.
                – queued
                May 6 '17 at 16:20












                @queued cron manages the tabs in exactly the way you describe (only one file per user though, by design). Have a look in /var/cron/tabs (it may be a different folder on your system). This is not to be modified through other means than by the crontab command though, so anything you build will have to use that. You could obviously also have a system where you have multiple crontabs per user, but you would need to concatenate these to have them activated by cron.
                – Kusalananda
                May 6 '17 at 16:24






                @queued cron manages the tabs in exactly the way you describe (only one file per user though, by design). Have a look in /var/cron/tabs (it may be a different folder on your system). This is not to be modified through other means than by the crontab command though, so anything you build will have to use that. You could obviously also have a system where you have multiple crontabs per user, but you would need to concatenate these to have them activated by cron.
                – Kusalananda
                May 6 '17 at 16:24














                My point is: I don't get the design that allows only one file per user. Is it intended, by some acceptable reasons?
                – queued
                May 6 '17 at 16:44




                My point is: I don't get the design that allows only one file per user. Is it intended, by some acceptable reasons?
                – queued
                May 6 '17 at 16:44




                1




                1




                Now I got the point. I misinterpreted the program cron as the only way to run programs periodically, though it actually was just one of the programs that does the thing with a simple interface. I think I should make another program that periodically runs programs, or simply make a folder and make a cron job to run-parts it as you mentioned.
                – queued
                May 6 '17 at 17:32




                Now I got the point. I misinterpreted the program cron as the only way to run programs periodically, though it actually was just one of the programs that does the thing with a simple interface. I think I should make another program that periodically runs programs, or simply make a folder and make a cron job to run-parts it as you mentioned.
                – queued
                May 6 '17 at 17:32












                up vote
                1
                down vote













                Your current cron implementation probably supports /etc/cron.d, where jobs have an additional "run as" user specified after the regular time fields and before the command. So, just adjust your interface to create files in that directory like regular cron entries with the username (perhaps extracted from the loginuid) prepended after the fifth field. Then you can do one job per file. :)



                Look at man 5 crontab
                https://linux.die.net/man/5/crontab



                Note that the main problem with this is that a user who can edit files in that directory could create a file which runs as root. So, you probably want a wrapper script run via sudo which will validate the input and force the calculated username into the generated file. And then got need to make sure you're doing things securely within the script, like not trusting $PATH, etc.



                PS, in a shell script: getent passwd $(</proc/self/loginuid)



                Honestly, if you're making users know the cron time format, a few extra seconds to teach them to use crontab -e (and set $EDITOR if vi is scary) isn't terribly difficult.






                share|improve this answer



























                  up vote
                  1
                  down vote













                  Your current cron implementation probably supports /etc/cron.d, where jobs have an additional "run as" user specified after the regular time fields and before the command. So, just adjust your interface to create files in that directory like regular cron entries with the username (perhaps extracted from the loginuid) prepended after the fifth field. Then you can do one job per file. :)



                  Look at man 5 crontab
                  https://linux.die.net/man/5/crontab



                  Note that the main problem with this is that a user who can edit files in that directory could create a file which runs as root. So, you probably want a wrapper script run via sudo which will validate the input and force the calculated username into the generated file. And then got need to make sure you're doing things securely within the script, like not trusting $PATH, etc.



                  PS, in a shell script: getent passwd $(</proc/self/loginuid)



                  Honestly, if you're making users know the cron time format, a few extra seconds to teach them to use crontab -e (and set $EDITOR if vi is scary) isn't terribly difficult.






                  share|improve this answer

























                    up vote
                    1
                    down vote










                    up vote
                    1
                    down vote









                    Your current cron implementation probably supports /etc/cron.d, where jobs have an additional "run as" user specified after the regular time fields and before the command. So, just adjust your interface to create files in that directory like regular cron entries with the username (perhaps extracted from the loginuid) prepended after the fifth field. Then you can do one job per file. :)



                    Look at man 5 crontab
                    https://linux.die.net/man/5/crontab



                    Note that the main problem with this is that a user who can edit files in that directory could create a file which runs as root. So, you probably want a wrapper script run via sudo which will validate the input and force the calculated username into the generated file. And then got need to make sure you're doing things securely within the script, like not trusting $PATH, etc.



                    PS, in a shell script: getent passwd $(</proc/self/loginuid)



                    Honestly, if you're making users know the cron time format, a few extra seconds to teach them to use crontab -e (and set $EDITOR if vi is scary) isn't terribly difficult.






                    share|improve this answer














                    Your current cron implementation probably supports /etc/cron.d, where jobs have an additional "run as" user specified after the regular time fields and before the command. So, just adjust your interface to create files in that directory like regular cron entries with the username (perhaps extracted from the loginuid) prepended after the fifth field. Then you can do one job per file. :)



                    Look at man 5 crontab
                    https://linux.die.net/man/5/crontab



                    Note that the main problem with this is that a user who can edit files in that directory could create a file which runs as root. So, you probably want a wrapper script run via sudo which will validate the input and force the calculated username into the generated file. And then got need to make sure you're doing things securely within the script, like not trusting $PATH, etc.



                    PS, in a shell script: getent passwd $(</proc/self/loginuid)



                    Honestly, if you're making users know the cron time format, a few extra seconds to teach them to use crontab -e (and set $EDITOR if vi is scary) isn't terribly difficult.







                    share|improve this answer














                    share|improve this answer



                    share|improve this answer








                    edited May 6 '17 at 22:55

























                    answered May 6 '17 at 22:50









                    dannysauer

                    82748




                    82748






















                        up vote
                        0
                        down vote













                        If you want a cron entry:



                        0 * * * * my_script


                        then I recommend you think of a separate name for your cron management function, like, "cron_mgmt", whose first argument is a SWITCH in a CASE statement:



                        cron_mgmt () {

                        case $1 in
                        add ) ... ;;
                        list ) ...;;
                        remove ) ...
                        help ) ...
                        * ) echo "You need help. Here it is"
                        cron_mgmt help
                        ;;
                        esac
                        }





                        share|improve this answer



























                          up vote
                          0
                          down vote













                          If you want a cron entry:



                          0 * * * * my_script


                          then I recommend you think of a separate name for your cron management function, like, "cron_mgmt", whose first argument is a SWITCH in a CASE statement:



                          cron_mgmt () {

                          case $1 in
                          add ) ... ;;
                          list ) ...;;
                          remove ) ...
                          help ) ...
                          * ) echo "You need help. Here it is"
                          cron_mgmt help
                          ;;
                          esac
                          }





                          share|improve this answer

























                            up vote
                            0
                            down vote










                            up vote
                            0
                            down vote









                            If you want a cron entry:



                            0 * * * * my_script


                            then I recommend you think of a separate name for your cron management function, like, "cron_mgmt", whose first argument is a SWITCH in a CASE statement:



                            cron_mgmt () {

                            case $1 in
                            add ) ... ;;
                            list ) ...;;
                            remove ) ...
                            help ) ...
                            * ) echo "You need help. Here it is"
                            cron_mgmt help
                            ;;
                            esac
                            }





                            share|improve this answer














                            If you want a cron entry:



                            0 * * * * my_script


                            then I recommend you think of a separate name for your cron management function, like, "cron_mgmt", whose first argument is a SWITCH in a CASE statement:



                            cron_mgmt () {

                            case $1 in
                            add ) ... ;;
                            list ) ...;;
                            remove ) ...
                            help ) ...
                            * ) echo "You need help. Here it is"
                            cron_mgmt help
                            ;;
                            esac
                            }






                            share|improve this answer














                            share|improve this answer



                            share|improve this answer








                            edited May 6 '17 at 15:08









                            Stephen Rauch

                            3,318101328




                            3,318101328










                            answered May 6 '17 at 14:58









                            Marty McGowan

                            1292




                            1292






















                                up vote
                                0
                                down vote













                                Rather than roll your own interface, keep it simple. To install a cron job with a certain schedule, place it in a certain directory. To remove it, remove it from the directory. You don't need to provide users with any tools to do that, just tell them which directory to put their job in.



                                This is how most Linux distributions manage system cron jobs that can be installed by individual packages. Debian, Fedora, Arch Linux and others ship a tool called run-parts whose job is to run the scripts in a particular directory one by one. The different implementations of run-parts have different rules on exactly which file names are acceptable for scripts. If you don't want to depend on this, you can roll your own:



                                for x in /path/to/daily-jobs/*; do
                                if [ -x "$x" ]; then
                                case "${x##*/}" in
                                *[!-0-9A-Z_a-z]*) :;; # skip file names containing "weird" characters
                                *) "$x";;
                                esac
                                fi
                                done


                                If you want to allow users to specify their own schedule, then this approach won't work. You need to rebuild the crontab file each time a new job is submitted. This can be done, but is complicated to set up reliably. However, if users can specify their own schedule, then there's little reason to add another interface on top of crontab -e, or a GUI that calls crontab -e under the hood.






                                share|improve this answer

























                                  up vote
                                  0
                                  down vote













                                  Rather than roll your own interface, keep it simple. To install a cron job with a certain schedule, place it in a certain directory. To remove it, remove it from the directory. You don't need to provide users with any tools to do that, just tell them which directory to put their job in.



                                  This is how most Linux distributions manage system cron jobs that can be installed by individual packages. Debian, Fedora, Arch Linux and others ship a tool called run-parts whose job is to run the scripts in a particular directory one by one. The different implementations of run-parts have different rules on exactly which file names are acceptable for scripts. If you don't want to depend on this, you can roll your own:



                                  for x in /path/to/daily-jobs/*; do
                                  if [ -x "$x" ]; then
                                  case "${x##*/}" in
                                  *[!-0-9A-Z_a-z]*) :;; # skip file names containing "weird" characters
                                  *) "$x";;
                                  esac
                                  fi
                                  done


                                  If you want to allow users to specify their own schedule, then this approach won't work. You need to rebuild the crontab file each time a new job is submitted. This can be done, but is complicated to set up reliably. However, if users can specify their own schedule, then there's little reason to add another interface on top of crontab -e, or a GUI that calls crontab -e under the hood.






                                  share|improve this answer























                                    up vote
                                    0
                                    down vote










                                    up vote
                                    0
                                    down vote









                                    Rather than roll your own interface, keep it simple. To install a cron job with a certain schedule, place it in a certain directory. To remove it, remove it from the directory. You don't need to provide users with any tools to do that, just tell them which directory to put their job in.



                                    This is how most Linux distributions manage system cron jobs that can be installed by individual packages. Debian, Fedora, Arch Linux and others ship a tool called run-parts whose job is to run the scripts in a particular directory one by one. The different implementations of run-parts have different rules on exactly which file names are acceptable for scripts. If you don't want to depend on this, you can roll your own:



                                    for x in /path/to/daily-jobs/*; do
                                    if [ -x "$x" ]; then
                                    case "${x##*/}" in
                                    *[!-0-9A-Z_a-z]*) :;; # skip file names containing "weird" characters
                                    *) "$x";;
                                    esac
                                    fi
                                    done


                                    If you want to allow users to specify their own schedule, then this approach won't work. You need to rebuild the crontab file each time a new job is submitted. This can be done, but is complicated to set up reliably. However, if users can specify their own schedule, then there's little reason to add another interface on top of crontab -e, or a GUI that calls crontab -e under the hood.






                                    share|improve this answer












                                    Rather than roll your own interface, keep it simple. To install a cron job with a certain schedule, place it in a certain directory. To remove it, remove it from the directory. You don't need to provide users with any tools to do that, just tell them which directory to put their job in.



                                    This is how most Linux distributions manage system cron jobs that can be installed by individual packages. Debian, Fedora, Arch Linux and others ship a tool called run-parts whose job is to run the scripts in a particular directory one by one. The different implementations of run-parts have different rules on exactly which file names are acceptable for scripts. If you don't want to depend on this, you can roll your own:



                                    for x in /path/to/daily-jobs/*; do
                                    if [ -x "$x" ]; then
                                    case "${x##*/}" in
                                    *[!-0-9A-Z_a-z]*) :;; # skip file names containing "weird" characters
                                    *) "$x";;
                                    esac
                                    fi
                                    done


                                    If you want to allow users to specify their own schedule, then this approach won't work. You need to rebuild the crontab file each time a new job is submitted. This can be done, but is complicated to set up reliably. However, if users can specify their own schedule, then there's little reason to add another interface on top of crontab -e, or a GUI that calls crontab -e under the hood.







                                    share|improve this answer












                                    share|improve this answer



                                    share|improve this answer










                                    answered May 6 '17 at 22:30









                                    Gilles

                                    525k12710511578




                                    525k12710511578






























                                        draft saved

                                        draft discarded




















































                                        Thanks for contributing an answer to Unix & Linux Stack Exchange!


                                        • Please be sure to answer the question. Provide details and share your research!

                                        But avoid



                                        • Asking for help, clarification, or responding to other answers.

                                        • Making statements based on opinion; back them up with references or personal experience.


                                        To learn more, see our tips on writing great answers.





                                        Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


                                        Please pay close attention to the following guidance:


                                        • Please be sure to answer the question. Provide details and share your research!

                                        But avoid



                                        • Asking for help, clarification, or responding to other answers.

                                        • Making statements based on opinion; back them up with references or personal experience.


                                        To learn more, see our tips on writing great answers.




                                        draft saved


                                        draft discarded














                                        StackExchange.ready(
                                        function () {
                                        StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f363376%2fhow-do-i-add-remove-cron-jobs-by-script%23new-answer', 'question_page');
                                        }
                                        );

                                        Post as a guest















                                        Required, but never shown





















































                                        Required, but never shown














                                        Required, but never shown












                                        Required, but never shown







                                        Required, but never shown

































                                        Required, but never shown














                                        Required, but never shown












                                        Required, but never shown







                                        Required, but never shown







                                        Popular posts from this blog

                                        Accessing regular linux commands in Huawei's Dopra Linux

                                        Can't connect RFCOMM socket: Host is down

                                        Kernel panic - not syncing: Fatal Exception in Interrupt