Search code examples
bashpersistence

How to store state between two consecutive runs of a bash script


I have bash script which runs using a cron job every minute. I would like to save the script's state for reuse in the next run.

What would be the best way to save the state (in this case a variable which is assigned a number); so in the next run, the number can be compared with the value from previous runs.


Solution

  • Example of saving and reloading variable value from file

    #!/usr/bin/env bash
    
    # The file holding persistent variable value
    statefile='/var/statefile'
    
    # Declare our variable as holding an integer
    declare -i persistent_counter
    
    # If the persistence file exists, read the variable value from it
    if [ -f "$statefile" ]; then
      read -r persistent_counter <"$statefile"
    else
      persistent_counter=0
    fi
    
    # Update counter
    persistent_counter="$((persistent_counter + 1))"
    
    # Save value to file
    printf '%d\n' "$persistent_counter" >"$statefile"
    

    Another way with sourcing:

    #!/usr/bin/env bash
    
    # The file holding persistent variable value
    statefile='/var/statefile'
    
    # Source the statefile
    . "$statefile" 2>/dev/null || :
    
    # Declare our variable as holding an integer
    declare -i persistent_counter
    
    # Assign default value if unset
    : ${persistent_counter:=0}
    
    # Update counter
    persistent_counter="$((persistent_counter + 1))"
    
    # Persist variable to file
    declare -p persistent_counter >"$statefile"
    

    Persisting multiple variables (an integer, a string and an array):

    #!/usr/bin/env bash
    
    # The file holding persistent variable value
    statefile='/tmp/statefile'
    
    # Initialize variables even if they are later state restored
    persistent_counter=0
    persistent_last_date="never"
    persistent_array=()
    
    save_state () {
      typeset -p "$@" >"$statefile"
    }
    
    # Source the statefile to restore state
    . "$statefile" 2>/dev/null || :
    
    # Set save_state call on script exit to automatically persist state
    trap 'save_state persistent_counter persistent_last_date persistent_array' EXIT
    
    # Display restored variables
    printf 'Last time script ran was: %s\n' "$persistent_last_date"
    printf 'Counter was: %d\n' "$persistent_counter"
    printf 'Array contained %d elements:\n' "${#persistent_array[@]}"
    printf '%s\n' "${persistent_array[@]}"
    
    # Update counter
    persistent_counter="$((persistent_counter + 1))"
    
    # Update Array
    if ! [ "$persistent_last_date" = 'never' ]; then
      persistent_array+=("$persistent_last_date")
    fi
    
    # Update last run time
    persistent_last_date="$(date -R)"
    
    # Now that the script exit, it will automatically trap call save_state