How can I cause a script to log in a separate file the number of times it has been executed?

I assume you want to have a single file countfile that only contains one single number representing the execution counter.

You can read this counter into a shell variable $counter e.g. using one of these lines:

  • read counter < countfile
    
  • counter=$(cat countfile)
    

Simple integer additions can be done in Bash itself using the $(( EXPRESSION )) syntax. Then simply write the result back to our countfile:

echo "$(( counter + 1 ))" > countfile

You should probably also safeguard your script for the case that countfile doesn't exist yet and create one initialized with the value 1 then.

The whole thing might look like this:

#!/bin/bash
if [[ -f countfile ]] ; then
    read counter < countfile
else
    counter=0
fi
echo "$(( counter + 1 ))" > countfile

Just let the script create a log file, add for example a line in your script at the end:

echo "Script has been executed at $(date +\%Y-\%m-\%d) $(date +\%H-\%M-\%S)" >> ~/script.log

This way you can format the way you present date and time yourself, but if you simply want to go with a full date and time (and HH:MM:SS is an acceptable format for you) you can as well simply use:

echo "Script has been executed at $(date +\%F-\%T)" >> ~/script.log

Then you could do:

wc -l ~/script.log

Which counts the newline characters and give you an estimate of how many lines are inside the log file. Up to that you can see within the log file even when it was executed. To adapt it for your needs, you can change the paths and names used for logging. I just did an example here which saves the logfile in ~.

So for example you want the script add this count to the line you added at the end of your script you could do something like this at the start of your script:

count=$(( $(wc -l ~/script.log | awk '{print $1}') + 1 ))
# the next line can be simply skipped if you not want an output to std_out
echo "Script execution number: $count"

And change your line at the end of the script to something including even that information:

echo "Script has been executed $count times at $(date +\%F-\%T)" >> ~/script.log

This solution uses the same approach as Byte Commander’s answer but it doesn't rely on shell arithmetic or other Bashisms.

exec 2>&3 2>/dev/null
read counter < counter.txt || counter=0
exec 3>&2 3>&-
expr "$counter" + 1 > counter.txt

The stream redirections

  1. duplicate the standard error stream (2) to a different file descriptor (3),
  2. replace it (2) with a redirection to /dev/null (to suppress the error message in the subsequent redirection of the input of the read command if the counter file is missing expectedly),
  3. later duplicate the original standard error stream (now at 3) back into place (2) and
  4. close the copy of the standard error stream (3).