Search code examples
timestampshposixpid

Is there a POSIX way to get the starting time of a given PID from the shell?


I have a file whose content is PID Tab STARTTIME and I would like to know if that process is still alive.

I can check that a given PID is running with:

kill -0 "$pid" && echo alive

But it lacks the ability to differentiate between the real process and an other one that got the same PID.

So I though of using ps:

ps -o lstart= -p "$pid"

But it errputs:

ps: unknown output format: -o lstart

Is there a POSIX way to get the starting time (in seconds since EPOCH) of a given PID from the shell?


Solution

  • As @Cyrus pointed out, it's possible to use the output of ps -o etime= to calculate the starting time of a given PID:

    edit: as @KamilCuk suggested, the functions now use a shell pipe instead of dealing with the ps call from inside awk.

    # usage: starttime PID
    starttime() {
        command -p ps -o etime= -p "$1" |
        command -p awk '
            BEGIN { srand(); timeofday = srand() }
            END {
                if (NF) {
                    n = split($NF, a, "[:-]")
                    print timeofday - a[n-3]*86400 - a[n-2]*3600 - a[n-1]*60 - a[n]
                } else
                    exit 1
            }
        '
    }
    

    But it's more like an approximation, because when I compare it to the starting "date" provided by ps -o lstart= in Linux, I don't get identical results; as shown by the following script that outputs both values for all the running processes:

    #!/bin/bash
    
    starttime() { ... }
    
    while read pid lstart
    do
        t1=$(date -d "$lstart" +%s) &&
        t2=$(starttime "$pid") &&
        printf '%s\t%s\n' "$t1" "$t2"
    done < <(
        ps -o pid= -o lstart= -e
    )
    
    1681318132  1681318133
    1681133418  1681133419
    1681133418  1681133418
    1681318132  1681318132
    ...
    

    While the results are certainly different, the difference doesn't exceed 1 second; therefore, I think that we can still use ps -o etime= for checking that a process is alive in an environment that doesn't require much precision (for ex. a cron job). Here's a function that "allows" a ±1 second delta:

    tested on AIX/Solaris/macOS/FreeBSD/Linux

    # usage: is_alive PID STARTTIME
    is_alive() {
        command -p ps -o etime= -p "$1" |
        command -p awk -v starttime="$2" '
            BEGIN { srand(); timeofday = srand() }
            END {
                n = split($NF, a, "[:-]")
                d = starttime - timeofday + a[n-3]*86400 + a[n-2]*3600 + a[n-1]*60 + a[n]
                exit( -1 < d || d > 1 )
            }
        '
    }