데이터 테이블에서 일치하는 레코드 간의 쌍별 시간 차이를 계산합니다.

데이터 테이블에서 일치하는 레코드 간의 쌍별 시간 차이를 계산합니다.

다음 형식의 3열 데이터가 있습니다.

TIME        MPID    CPID
16:45:51    10051   77845
16:45:51    10051   77845
16:46:52    10051   77846
16:46:53    10051   77846
16:48:38    10051   77847
16:48:38    10051   77847
16:48:39    10051   77995
16:49:31    10051   77848
16:49:31    10051   77848
16:51:03    10051   77849
16:51:03    10051   77849

여기서 TIME 열은 HH:MM:SS 형식의 타임스탬프로 구성됩니다. MPID 및 CPID 열은 식별 번호입니다. 그 의미는 내 질문에 중요하지 않습니다. MPID 값도 데이터 세트에 존재하고 출력에 전파되어야 한다는 사실을 제외하고는 작동하지 않습니다.

내가 원하는 것은 CPID 값이 일치하는 행 쌍을 식별하고 해당 시간 간의 차이를 계산하는 것입니다. 예를 들어, 위의 예에는 CPID가 77846인 두 개의 행(세 번째 및 네 번째 행)이 있습니다. 해당 시간은 16:46:52와 16:46:53이므로 차이를 계산하고 싶습니다.

16:46:53 - 16:46:52 = 00:00:01

또한 이 결과를 다음 형식으로 출력하고 싶습니다.

MPID 10051 CPID 77846 Total time difference: 01 seconds

주어진 CPID가 데이터 세트에 정확히 두 번 나타나지 않으면 이를 무시하고 싶습니다.

샘플 데이터가 주어진 경우 원하는 출력은 다음과 같아야 합니다.

MPID 10051 CPID 77845 Total time difference: 00 seconds
MPID 10051 CPID 77846 Total time difference: 01 seconds
MPID 10051 CPID 77847 Total time difference: 00 seconds
MPID 10051 CPID 77848 Total time difference: 00 seconds
MPID 10051 CPID 77849 Total time difference: 00 seconds

답변1

  1. 가설입력하다uniq -D모든 중복 라인을 표시 하는 데 사용되는 차등 파일입니다.세 번째 장소필드오직, 제목도 제거됩니다. 그런 다음 date 형식을 사용하여 %s시간을 초로 변환하고 뺍니다. 나머지는 표준이다껍데기:

    uniq -D -f 2 input | 
    while read a b c && read d e f ; do 
        g=$(( $(date -d $d +%s) - $(date -d $a +%s) ))
        printf "MPID %s CPID %s Total time difference: %02i seconds\n" $b $c $g
    done
    

    산출:

    MPID 10051 CPID 77845 Total time difference: 00 seconds
    MPID 10051 CPID 77846 Total time difference: 01 seconds
    MPID 10051 CPID 77847 Total time difference: 00 seconds
    MPID 10051 CPID 77848 Total time difference: 00 seconds
    MPID 10051 CPID 77849 Total time difference: 00 seconds
    
  2. 이전 사양(기준:OP 코멘트), 더 많은 코드가 필요합니다:

    uniq -D -f 2 input | 
    while read a b c && read d e f ; do 
        g=$(( $(date -d $d +%s) - $(date -d $a +%s) ))
        printf "For %s %s time difference: %02i:%02i:%02i\n" \
                $b $c $((g/360)) $(((g/60)%60)) $((g%60))
    done
    

    산출:

    For 10051 77845 time difference: 00:00:00
    For 10051 77846 time difference: 00:00:01
    For 10051 77847 time difference: 00:00:00
    For 10051 77848 time difference: 00:00:00
    For 10051 77849 time difference: 00:00:00
    

답변2

원하는 작업을 수행하는 대략적인 쉘 스크립트는 다음과 같습니다.

#!/bin/bash

# pairwise_pid_time_diff.sh

# Write the data to a temporary file, sorted first by pid and then by time
cat "${1}" | sed 's/\s\+/ /g' | sort -k3,3 -k1,1 -n > sorted_pids.csv

# Compute the pair-wise time differences
for pid in $(cat sorted_pids.csv | cut -d' ' -f3 | uniq); do
    if (( "$(grep "${pid}" sorted_pids.csv | wc -l)" == 2 )); then
        time1_string="$(cat sorted_pids.csv | grep "${pid}" | head -1 | cut -d' ' -f1)"
        time2_string="$(cat sorted_pids.csv | grep "${pid}" | tail -1 | cut -d' ' -f1)"
        time1_seconds="$(date -u -d "${time1_string}" +"%s")"
        time2_seconds="$(date -u -d "${time2_string}" +"%s")"
        date -u -d "0 ${time2_seconds} sec - ${time1_seconds} sec" +"%H:%M:%S"
    fi
done

# Delete the temporary file
rm sorted_pids.csv

이를 테스트하기 위해 샘플 데이터를 파일에 씁니다.

cat <<HEREDOC > pids.csv
16:45:51 10051 77845
16:45:51 10051 77845
16:46:52 10051 77846
16:46:53 10051 77846
16:48:38 10051 77847
16:48:38 10051 77847
16:48:39 10051 77995
16:49:31 10051 77848
16:49:31 10051 77848
16:51:03 10051 77849
16:51:03 10051 77849
HEREDOC

그런 다음 스크립트를 실행합니다.

bash pairwise_pid_time_diff.sh pids.csv

이는 다음과 같은 결과를 제공합니다.

00:00:00
00:00:01
00:00:00
00:00:00
00:00:00

스크립트를 실행하는 데 문제가 있는 것 같으므로 다음은 디버깅 목적을 위한 다른 버전입니다.

#!/bin/bash

# pairwise_pid_time_diff_debug.sh

# Write the data to a temporary file, sorted first by pid and then by time
1>&2 echo "Writing sorted data to temporary file."
cat "${1}" | sed 's/\s\+/ /g' | sort -k3,3 -k1,1 -n > sorted_pids.csv

# Compute the pair-wise time differences
1>&2 echo "Entering main loop..."
for pid in $(cat sorted_pids.csv | cut -d' ' -f3 | uniq); do
    1>&2 echo "Looking at pid: ${pid}"

    if (( "$(grep "${pid}" sorted_pids.csv | wc -l)" == 2 )); then
        1>&2 echo "Found matching pair."

        time1_string="$(cat sorted_pids.csv | grep "${pid}" | head -1 | cut -d' ' -f1)"
        1>&2 echo "Time 1 string: ${time1_string}"

        time2_string="$(cat sorted_pids.csv | grep "${pid}" | tail -1 | cut -d' ' -f1)"
        1>&2 echo "Time 2 string: ${time2_string}"

        time1_seconds="$(date -u -d "${time1_string}" +"%s")"
        1>&2 echo "Time 1 in seconds: ${time1_seconds}"

        time2_seconds="$(date -u -d "${time2_string}" +"%s")"
        1>&2 echo "Time 1 in seconds: ${time2_seconds}"

        time_difference="$(date -u -d "0 ${time2_seconds} sec - ${time1_seconds} sec" +"%H:%M:%S")"
        echo "${time_difference}"
    fi
done

# Delete the temporary file
rm sorted_pids.csv
1>&2 echo "Deleted temporary file."

이 스크립트를 실행하면 다음과 같은 결과가 나타납니다.

bash pairwise_pid_time_diff_debug.sh pids.csv
Writing sorted data to temporary file.
Entering main loop...
Looking at pid: 77845
Found matching pair.
Time 1 string: 16:45:51
Time 2 string: 16:45:51
Time 1 in seconds: 1510332351
Time 1 in seconds: 1510332351
00:00:00
Looking at pid: 77846
Found matching pair.
Time 1 string: 16:46:52
Time 2 string: 16:46:53
Time 1 in seconds: 1510332412
Time 1 in seconds: 1510332413
00:00:01
Looking at pid: 77847
Found matching pair.
Time 1 string: 16:48:38
Time 2 string: 16:48:38
Time 1 in seconds: 1510332518
Time 1 in seconds: 1510332518
00:00:00
Looking at pid: 77995
Looking at pid: 77848
Found matching pair.
Time 1 string: 16:49:31
Time 2 string: 16:49:31
Time 1 in seconds: 1510332571
Time 1 in seconds: 1510332571
00:00:00
Looking at pid: 77849
Found matching pair.
Time 1 string: 16:51:03
Time 2 string: 16:51:03
Time 1 in seconds: 1510332663
Time 1 in seconds: 1510332663
00:00:00
Deleted temporary file.

스크립트를 실행하는 대신 수동으로 프로세스를 단계별로 진행해 보겠습니다. 먼저 데이터 파일을 만들어 보겠습니다.

cat <<HEREDOC > pids.csv
16:45:51 10051 77845
16:45:51 10051 77845
16:46:52 10051 77846
16:46:53 10051 77846
16:48:38 10051 77847
16:48:38 10051 77847
16:48:39 10051 77995
16:49:31 10051 77848
16:49:31 10051 77848
16:51:03 10051 77849
16:51:03 10051 77849
HEREDOC

다음으로 데이터를 먼저 PID별로 정렬한 다음 시간별로 정렬해 보겠습니다.

cat pids.csv | sed 's/\s\+/ /g' | sort -k3,3 -k1,1 -n > sorted_pids.csv

파일이 올바르게 작성되었는지 확인해 보겠습니다.

cat sorted_pids.csv

다음과 같은 결과가 나와야 합니다.

16:45:51 10051 77845
16:45:51 10051 77845
16:46:52 10051 77846
16:46:53 10051 77846
16:48:38 10051 77847
16:48:38 10051 77847
16:49:31 10051 77848
16:49:31 10051 77848
16:51:03 10051 77849
16:51:03 10051 77849
16:48:39 10051 77995

이제 데이터에서 고유한 PID를 가져오겠습니다.

user@host:~$ cat sorted_pids.csv | cut -d' ' -f3 | uniq

77845
77846
77847
77848
77849
77995

첫 번째 PID: 77845의 시차를 계산해 보겠습니다.

먼저 77845의 첫 번째 시간 문자열을 가져옵니다.

time1_string="$(cat sorted_pids.csv | grep 77845 | head -1 | cut -d' ' -f1)"

우리의 값이 올바른지 확인해 봅시다:

user@host:~$ echo ${time1_string} 

16:45:51

이제 이것을 초로 변환해 보겠습니다.

time1_seconds="$(date -u -d "${time1_string}" +"%s")"

그리고 우리가 얻은 값을 확인하십시오.

user@host:~$ echo ${time1_seconds}

1510332351

이제 두 번째로 문자열을 사용하여 동일한 작업을 수행해 보겠습니다.

time2_string="$(cat sorted_pids.csv | grep 77845 | tail -1 | cut -d' ' -f1)"
time2_seconds="$(date -u -d "${time2_string}" +"%s")"
user@host:~$ echo "${time2_string}"

16:45:51

user@host:~$ echo "${time2_seconds}"

1510332351

이제 차이를 초 단위로 계산하고 이를 박자 기호로 변환합니다.

difference=$(date -u -d "0 ${time2_seconds} sec - ${time1_seconds} sec" +"%H:%M:%S")

결과를 확인하십시오.

00:00:00

관련 정보