4

I have a crontab that runs like this:

0 0 * * * /execute/shell/script.sh
0 0 * * * /execute/shell/script1.sh
0 0 * * * /execute/shell/script2.sh

And, I want to launch each script in a different screen. But I want to keep that screen running so that anytime I want to see the progress of one of these scripts, I can always just do screen -d -r <PID> and it will reattach the screen for me to ssee the progress.

I'm sure there must be a way to do this. but the similar questions i've found have not answered it.

Crontab start a screen How do I use crontab to start a screen session?

makansij
  • 255
  • 4
  • 11
  • I looked at the similar questions that you quote, and they seem to have decent solutions; it's not very clear how what you want to do is any different -- in fact, it'd probably be a much better idea to use named sessions (as in those sample answers) instead of PIDs. – cnst Sep 12 '17 at 05:24
  • 1
    Log files. They're not just a good idea, they're THE LAW. – womble Sep 14 '17 at 03:08
  • Cron is generally not expected to run jobs in terminals. Is there a reason why you want to use screen, rather than just piping output to files? You could track those with `tail -f` if you want to watch progress as it happens. – mc0e Sep 14 '17 at 15:23

3 Answers3

3

Do you actually have to interact with the commands, or do you just want to see the status before the commands complete, and the results are mailed back to you?

I've encountered a similar "issue", where I was running traceroute(8) and mtr from within cron, to monitor connectivity, with mtr running in a for-loop to provide more precise measurements over a given interval (between 5 and 16.67 minutes (300 to 1000 cycles)), but the whole script designed to run for about an hour (to ensure I don't get spammed with emails), so, I wanted to be able to see the status as it happened.

https://unix.stackexchange.com/questions/61820/how-can-i-access-a-deleted-open-file-on-linux-output-of-a-running-crontab-task

The way cron works is it creates a temporary file in /tmp, and immediately calls unlink(2) (but still keeping the file open); this is subsequently used to store the output of your scripts before they finish, and it gets emailed to you.

As such, you can use lsof -n -c cron (and/or lsof -n | fgrep cron) to find out the number of open files that have been deleted, and then access those files via the /proc/$PID/fd/$FD namespace to see the output of your scripts running from within cron, without any need for screen.

cnst
  • 12,948
  • 7
  • 51
  • 75
  • I don't need it to write to a file, because i don't want to fill up disk space or anything. The scripts I have written have lots of `echo` and lots of output ( they are listening to ports, and spitting out statistics of what they are listening to). So, every morning, I want to log into the machine, and launch `screen` to be able to see the stats it is outputting in real time. the current way I'm doing this is that the shell scripts get executied of course, but I cannot see their output in realtime. Writing to a file is not ideal because it is not in real time. – makansij Sep 12 '17 at 00:49
  • @Hunle I am not writing anything to a file -- my `mtr` would only output stuff into stdout, which would then be emailed to me by `cron` at completion. The file stuff is entirely cron's internal way of doing this (at least on linux it is). If this doesn't work, and the solution to the other questions you quote don't cut it, either, then I'm not exactly sure what you're after -- why involve `cron` at all? Sounds like you should just run screen, and start each command manually, possibly using [`at(1)`](http://mdoc.su/-/at.1), or redirect to screen's tty as per [tty(1)](http://mdoc.su/-/tty.1). – cnst Sep 12 '17 at 05:15
  • If you pipe to file, you can watch that output in real-time using `tail -f ` – mc0e Sep 14 '17 at 15:28
2

You may try something like this:

cat /etc/cron.d/test
*/10 * * * * root screen -dmS script bash -c '/execute/shell/script.sh; exec bash'
*/10 * * * * root screen -dmS script1 bash -c '/execute/shell/script1.sh; exec bash'
*/10 * * * * root screen -dmS script2 bash -c '/execute/shell/script2.sh; exec bash'

It should work I believe. Sure, edit times to whatever you need.

Jaroslav Kucera
  • 1,435
  • 10
  • 16
2

The above (Jaroslav Kucera answer) will not work as intended because on the second invocation the commands will spawn new screen sessions with same names as the previous ones.

If you want to have always the same screen sessions for the same scripts then I would do it a bit more trickier.

I would run those sessions at @reboot cron with scripts that make a constant loop like

#!/bin/bash
while true; do
if [ -f /tmp/script1_enabled ]; then
    script1_function_or_command
    rm /tmp/script1_enabled
fi

sleep 60;
done 

Which would run each minute checking for the presence of named file in /tmp - if it exists then run the command, otherwise wait another minute.

The second part would be cron commands that create those files each day - working like a boolean flag to initiate the script invocation.

After the script is done the file would be removed. That way you can keep same sessions for your scripts, and still run it in intervals of your liking.

If the 60 second delay in the loop is too much for you (there is no way to precisely run the script at given time with this method as the sleep will be executed in unpredictable time), then you can set up inotifywait watches and execute scripts as soon as the file is created.

the cron would look like :

@reboot screen -dmS script1 /usr/local/bin/script1_watcher
@reboot screen -dmS script2 /usr/local/bin/script2_watcher
0 0 * * * touch /tmp/script1_enabled
15 */4 * * * touch /tmp/script2_enabled
bocian85
  • 822
  • 5
  • 10