0

I wish to create a shell script which will create files at the specific point of time in a day.

Example case. once the shell script is executed, at a particular time of the day files should be created in /tmp/work/ directory.

when the time is 01:00 Hrs, abc.txt should be created.

when the time is 06:00 Hrs, def.txt should be created.

when the time is 13:00 Hrs, hij.txt should be created.

when the time is 23:00 Hrs, xyz.txt should be created.

All files should have some content as "THIS IS TEST FILE." to make file size more than 0 bytes.

Is it possible to execute below at that point of time?

echo "THIS IS TEST FILE." > /tmp/work/abc.txt  ## at 01:00 Hrs
echo "THIS IS TEST FILE." > /tmp/work/def.txt  ## at 06:00 Hrs

so on...

Piyush
  • 818
  • 8
  • 17
  • 2
    Have a look at *"cron"* and its *"crontab"* https://www.computerhope.com/unix/ucrontab.htm – Mark Setchell Jun 19 '18 at 15:47
  • 1
    This looks like a heavily obfuscated "real need" (also see [XY problem](https://meta.stackexchange.com/questions/66377/what-is-the-xy-problem) ] The problem with this is that you will get very generic answers that are quite probably missing your actual issue. For example: do they need to be created each day at the same times? What about the numeric suffix in the file name, does it restart at 1 every day or do they keep on increasing? And so on. More detail == better answers. – fvu Jun 19 '18 at 15:52
  • "Run only once" (as edited)? Then it sounds like you want an `at` job, not a `cron` job. Again, we already have Q&A entries appropriate to task. – Charles Duffy Jun 19 '18 at 16:07
  • ...if you need something different than what we already have covered, be sure to explain, clearly, *why* the existing answers aren't suited to task (ideally, how you already tried to apply them, and how/why those attempts failed). – Charles Duffy Jun 19 '18 at 16:08
  • Maybe you should have added the **autosys** tag. – Mark Setchell Jun 19 '18 at 16:14
  • Argh -- edited to change the tags (adding "autosys", removing "shell") and *then* voted to re-open, but because the "shell" tag is no longer set, I no longer have a dupehammer and can't single-handedly reopen. :/ – Charles Duffy Jun 19 '18 at 17:18
  • @PiyushAnand ...to be clear, the problem with tagging this a shell question is that the generic best-practice shell answers appear not to be acceptable. This reads to me like what you want is something from an autosys expert, not a shell expert (though you haven't explained as much explicitly -- explicit feedback *would* be welcome). – Charles Duffy Jun 19 '18 at 17:20
  • Also -- how much accuracy do you need? Which **specific** version of bash? (If you're targeting a very new 4.x, there's a much more efficient way to check time than was possible earlier; running `date` is quite slow). – Charles Duffy Jun 19 '18 at 19:51
  • Can't add it here without more people voting to re-open the question, but see https://gist.github.com/charles-dyfis-net/d05f112e88be7577a29bd0493d1806e3 for an efficient answer that works with very new versions of bash. – Charles Duffy Jun 19 '18 at 19:57
  • @CharlesDuffy Voted for re-open too. – Mark Setchell Jun 19 '18 at 20:42

1 Answers1

2

Under most circumstances, you should use scheduling tools such as at or cron, as described in preexisting answers such as How to run a script at a certain time on Linux?; however, if you really need a long-running script, the following will run until end-of-day, polling the time.

Because it uses printf %(...)T -1 to check time instead of the date command, this polling is quite low-overhead (but requires bash 4.2 or newer). Reducing the polling rate, as by changing sleep 1 to sleep 60 would result in more efficient but slower cycle. Note that sleep is not guaranteed to wait the exact amount of time requested (especially on a heavily-loaded system, sleep 60 can sleep longer than the 60 seconds requested), so the checks for missed polling periods are important!

#!/usr/bin/env bash

case $BASH_VERSION in ''|[123].*|4.[01].*) echo "ERROR: Bash 4.2 or newer required" >&2; exit 1;; esac

declare -A timestops=(
  [01:00]="abc.txt"
  [06:00]="def.txt"
  [13:00]="hij.txt"
  [23:00]="xyz.txt"
)

printf -v run_on_date '%(%Y-%m-%d)T' -1

printf -v last_time '%(%H:%M)T' -1
while sleep 1; do
  printf -v curr_time '%(%H:%M)T' -1
  printf -v curr_date '%(%Y-%m-%d)T' -1
  [[ "$curr_time" = "$last_time" ]] && continue
  [[ "$curr_date" = "$run_on_date" ]] || { echo "Day ${run_on_date} has ended; exiting" >&2; exit 0; }
  for evt_ts in "${!timestops[@]}"; do
    if [[ $curr_time = "$evt_ts" ]] || [[ $curr_time > $evt_ts && $last_time < $evt_ts ]]; then
      evt_file=${timestops[$evt_ts]}
      echo "THIS IS TEST FILE." >"/tmp/work/$evt_file"
    fi
  done
  last_time=$curr_time
done
Charles Duffy
  • 280,126
  • 43
  • 390
  • 441