SoFunction
Updated on 2025-04-22

Use shell scripts to set up tasks in one second

Design a timed task management tool and implement it using Shell scripts. The core goal is to implement execution once a second and ensure that tasks are asynchronous and non-blocking. The following is the detailed design of the implementation:

Tool Functions

Task registration: Supports registration of new tasks.

Task Deletion: Supports deletion of existing tasks.

Task execution: Execute tasks once per second.

Asynchronous non-blocking: The task is executed in an independent process and does not affect the main process.

Logging: The task execution results are recorded in the log file.

Script Design

#!/bin/bash
 
# Configuration file and log file pathsCONFIG_FILE="./"
LOG_FILE="./"
PID_FILE="./"
RELOAD_SIGNAL_FILE="./"
 
# Initialize configuration files and signal filesif [ ! -f "$CONFIG_FILE" ]; then
    touch "$CONFIG_FILE"
fi
if [ -f "$RELOAD_SIGNAL_FILE" ]; then
    rm -f "$RELOAD_SIGNAL_FILE"
fi
 
# Task status tracking tabledeclare -A LAST_EXECUTION_TIMES
 
# Timed Schedulerscheduler() {
    echo $$ > "$PID_FILE"
    echo "Scheduler starts, PID: $$"
 
    while true; do
        # Check if the configuration needs to be reloaded        if [ -f "$RELOAD_SIGNAL_FILE" ]; then
            echo "$(date '+%Y-%m-%d %H:%M:%S') [INFO] Reload the configuration" >> "$LOG_FILE"
            LAST_EXECUTION_TIMES=()  # Clear the last execution record            rm -f "$RELOAD_SIGNAL_FILE"
        fi
 
        # Current timestamp        local current_time=$(date +%s)
 
        # Dynamically load configuration files and execute tasks        while IFS="=" read -r task_name interval command; do
            [ -z "$task_name" ] || [ -z "$interval" ] || [ -z "$command" ] && continue
 
            # Get the last execution time, if there is no record, the default is 0            local last_exec_time=${LAST_EXECUTION_TIMES[$task_name]:-0}
 
            # Determine whether the execution interval has reached            if (( current_time - last_exec_time >= interval )); then
                (   #Installing task name to record task execution status                    local TASK_LOG_FILE="$task_name/$(date '+%Y-%m-%d').log"
                    if [ ! -d "$(dirname "$TASK_LOG_FILE")" ]; then
                        mkdir -p "$(dirname "$TASK_LOG_FILE")"
                    fi
                    echo "$(date +'%H:%M:%S')implementstart" >> "$TASK_LOG_FILE"
                    eval "$command" >> "$TASK_LOG_FILE" 2>&1
                    echo "end" >> "$TASK_LOG_FILE"
                ) &
                LAST_EXECUTION_TIMES[$task_name]=$current_time  # Update the last execution time of the task            fi
        done < "$CONFIG_FILE"
 
        # Wait for 1 second        sleep 1
    done
}
 
# Stop the schedulerstop_scheduler() {
    if [ -f "$PID_FILE" ]; then
        local pid
        pid=$(cat "$PID_FILE")
        kill "$pid" && rm -f "$PID_FILE"
        echo "The scheduler has stopped"
    else
        echo "The scheduler is not running"
    fi
}
 
# Add a taskadd_task() {
    local task_name="$1"
    local interval="$2"
    local command="$3"
    if grep -q "^$task_name=" "$CONFIG_FILE"; then
        echo "Task '$task_name' Already exists"
        return 1
    fi
    echo "$task_name=$interval=$command" >> "$CONFIG_FILE"
    echo "Task '$task_name' Added successfully"
}
 
# Delete the taskremove_task() {
    local task_name="$1"
    if ! grep -q "^$task_name=" "$CONFIG_FILE"; then
        echo "Task '$task_name' Does not exist"
        return 1
    fi
    sed -i "/^$task_name=/d" "$CONFIG_FILE"
    echo "Task '$task_name' Deleted"
}
 
# Reload the configurationreload_scheduler() {
    if [ ! -f "$PID_FILE" ]; then
        echo "The scheduler is not running, configuration cannot be reloaded"
        return 1
    fi
    touch "$RELOAD_SIGNAL_FILE"
    echo "Configure reload signal sent"
}
 
# Show Helpshow_help() {
    echo "Usage: $0 [Command] [Parameters]"
    echo "Order:"
    echo "start start scheduler"
    echo "stop stop scheduler"
    echo "reload reload configuration file"
    echo "add task name seconds interval command Add task to configuration file"
    echo "remove task name Remove task from configuration file"
    echo " help show help"
}
 
# Main logiccase "$1" in
    start)
        scheduler
        ;;
    stop)
        stop_scheduler
        ;;
    reload)
        reload_scheduler
        ;;
    add)
        add_task "$2" "$3" "$4"
        ;;
    remove)
        remove_task "$2"
        ;;
    help|*)
        show_help
        ;;
esac

Configuration file format

Use file storage task configuration, one task per line, in the format:

Task name = seconds interval = command

For example:

task1=5=echo 'Run every 5 seconds'
task2=30=date
task3=10=sleep 2 && echo 'Task completed'

Start the scheduler

./ start

Add a task

./ add "task1" 5 "echo 'Hello, every 5 seconds!'"

Delete a task

./ remove "task1"

Reload the configuration

./ reload

Stop the scheduler

./ stop

At the same time, it supports manual configuration file modification tasks

Implementation principle

Task interval control: Use the associative array LAST_EXECUTION_TIMES to record the last execution time of each task.

Dynamic interval judgment: In a cycle per second, check whether the difference between the current time and the last execution time of the task reaches the set interval number of seconds.

Dynamic configuration management: The configuration file supports real-time modification, and can take effect immediately with the reload function.

Asynchronous execution: Each task executes independently of the process and does not block other tasks.

advantage

Supports custom intervals: meet the needs of different tasks execution frequencies.

Dynamic loading: Update task configuration without restarting.

High scalability: can be further optimized as needed, such as adding task priority or log cleaning capabilities.

Create a systemd service for the timer

Create a new systemd service file: You can place the service unit file in the /etc/systemd/system/ directory. Suppose we create a service called .

sudo nano /etc/systemd/system/

Edit service unit file: The following is the content template. You can modify it as needed.

[Unit]
Description=Task Scheduler Service
After=
 
[Service]
Type=simple
User=root
ExecStart=/path/to/your/ start
ExecReload=/path/to/your/ reload
ExecStop=/path/to/your/ stop
WorkingDirectory=/path/to/working/directory
Restart=always
RestartSec=5
StandardOutput=journal
StandardError=journal
SyslogIdentifier=task-scheduler
 
[Install]
WantedBy=

Reload systemd configuration: Let systemd recognize the new service unit file.

sudo systemctl daemon-reload

Enable Service: Set the service to start automatically when the system starts.

sudo systemctl enable 

Start the service: Start the task scheduler service immediately.

sudo systemctl start 

Check service status: Confirm whether the service starts normally.

sudo systemctl status 

Stop service:

sudo systemctl stop 

Reload the configuration (if you modify the configuration file or script):

sudo systemctl reload 

The service log can be viewed through the journalctl command for debugging:

sudo journalctl -u 

This is the end of this article about using shell scripts to self-timed tasks. For more relevant shell timing tasks, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!