bash v5 dan $EPOCHREALTIME
-
EPOCHREALTIME
nilai floating point dengan perincian mikro-detik -
EPOCHSECONDS
jumlah detik sejak Unix Epoch
Cara yang benar
Cukup:
IFS=. read ESEC NSEC <<<$EPOCHREALTIME
printf '%(%F:%T)T.%06.0f\n' $ESEC $NSEC
1. Tentang $EPOCHREALTIME
Harap peduli:
EPOCHREALTIME Each time this parameter is referenced, it expands to the number of seconds since the Unix Epoch (see time(3)) as a floating point value with micro-second granularity.
Jadi, jika saya meminta variabel yang sama dua kali di baris yang sama:
echo $EPOCHREALTIME... $EPOCHREALTIME
1572000683.886830... 1572000683.886840
atau lebih jelas:
printf "%s\n" ${EPOCHREALTIME#*.} ${EPOCHREALTIME#*.}
761893
761925
echo $(( -10#${EPOCHREALTIME#*.} + 10#${EPOCHREALTIME#*.} ))
37
Sama di raspberry-pi saya:
printf "%s\n" ${EPOCHREALTIME#*.} ${EPOCHREALTIME#*.}
801459
801694
echo $(( -10#${EPOCHREALTIME#*.} + 10#${EPOCHREALTIME#*.} ))
246
Jadi menanyakan dua kali ini untuk membangun bagian interger dan bagian fraksional proses terpisah dapat menyebabkan masalah:(Pada baris yang sama, akses pertama ke $ EPOCHREALTIME
dapat memberikan:NNN1.999995
, lalu berikutnya:NNN2.000002
. Hasilnya akan menjadi:NNN1.000002
dengan 1000000 kesalahan mikro-detik)
2. PERINGATAN! Tentang pencampuran $EPOCHSECONDS
dan $EPOCHREALTIME
Menggunakan keduanya bersama-sama tidak hanya menyebabkan bug yang disebutkan pertama!
$EPOCHSECONDS
gunakan panggilan ke time()
yang tidak diperbarui terus-menerus, sedangkan $EPOCHREALTIME
gunakan panggilan ke gettimeofday()
! Jadi hasilnya bisa sangat berbeda:
Saya menemukan jawaban ini untuk time() dan gettimeofday() mengembalikan detik yang berbeda dengan penjelasan yang bagus.
Jika saya mencoba di host saya:
epochVariableDiff () {
local errcnt=0 lasterrcnt v1 v2 v3 us vals line
while ((errcnt==0)) || ((errcnt>lasterrcnt)); do
lasterrcnt=$errcnt
printf -v vals '%(%s)T %s %s' -1 $EPOCHSECONDS $EPOCHREALTIME
IFS=$' .' read v1 v2 v3 us <<<"$vals"
[ "$v1" = "$v2" ] && [ "$v2" = "$v3" ] || ((errcnt++))
[ $errcnt -eq 1 ] && echo "$line"
printf -v line '%3d %s - %s - %s . %s' $errcnt $v1 $v2 $v3 $us
printf "%s\r" "$line"
((errcnt)) && echo "$line"
read -t ${1:-.0002}
done
}
(
Catatan:Saya menggunakan read -t
bukannya sleep
, karena sleep
tidak dibangun
Nota2:Anda bisa bermain dengan argumen fungsi untuk mengubah nilai batas waktu baca (tidur)
)
Ini bisa membuat sesuatu yang kecil:
$ epochVariableDiff .0002
0 1586851573 - 1586851573 - 1586851573 . 999894
1 1586851573 - 1586851573 - 1586851574 . 000277
2 1586851573 - 1586851573 - 1586851574 . 000686
3 1586851573 - 1586851573 - 1586851574 . 001087
4 1586851573 - 1586851573 - 1586851574 . 001502
5 1586851573 - 1586851573 - 1586851574 . 001910
6 1586851573 - 1586851573 - 1586851574 . 002309
7 1586851573 - 1586851573 - 1586851574 . 002701
8 1586851573 - 1586851573 - 1586851574 . 003108
9 1586851573 - 1586851573 - 1586851574 . 003495
10 1586851573 - 1586851573 - 1586851574 . 003899
11 1586851573 - 1586851573 - 1586851574 . 004400
12 1586851573 - 1586851573 - 1586851574 . 004898
13 1586851573 - 1586851573 - 1586851574 . 005324
14 1586851573 - 1586851573 - 1586851574 . 005720
15 1586851573 - 1586851573 - 1586851574 . 006113
16 1586851573 - 1586851573 - 1586851574 . 006526
17 1586851573 - 1586851573 - 1586851574 . 006932
18 1586851573 - 1586851573 - 1586851574 . 007324
19 1586851573 - 1586851573 - 1586851574 . 007733
19 1586851574 - 1586851574 - 1586851574 . 008144
Di mana bagian bilangan bulat dari $EPOCHREALTIME
dapat meningkat lebih dari 8000 mikrodetik sebelum $EPOCHSECONDS
(di host saya).
Catatan: Tampaknya ini terkait dengan beberapa bug , hasilnya bisa sangat berbeda antara host yang berbeda atau pada host yang sama setelah reboot, dan hal lainnya...Anehnya, saya dapat memperbanyaknya di banyak host berbeda (Intel Core,Intel Xeon, AMD64..) tetapi tidak pada raspberry pi! ? (Debian bash v5.0.3(1)-release yang sama), versi kernel yang berbeda.
Benar: Ini bukan bug! Mencampur time()
dan gettimeofday()
adalah bug!
Jadi, hindari menggunakan keduanya secara bersamaan !!!
3. Tentang printf "..%06.0f"
Catatan:Saya menggunakan %06.0f
bukannya %d
untuk memastikan $NSEC
untuk ditafsirkan sebagai desimal (mengambang), (mencegah interpretasi oktal jika variabel dimulai dengan 0
).
Bandingkan:
printf "nn.%06.0f\n" 012345
nn.012345
printf "nn.%06.0f\n" 098765
nn.098765
dan
printf "nn.%d\n" 012345
nn.5349
printf "nn.%d\n" 098765
-bash: printf: 098765: invalid octal number
nn.0
Contoh operasi
Tes kecil:
tunggu hingga detik berikutnya, lalu cetak waktu saat ini dengan mikrodetik
while ! read -t .$((1000000-10#${EPOCHREALTIME#*.})) foo; do
IFS=. read ESEC NSEC <<< $EPOCHREALTIME
printf '%(%F:%T)T.%06.0f\n' $ESEC $NSEC
done
Anda dapat mengakhiri pengujian ini dengan menekan Kembali
2019-10-25:13:16:46.000444
2019-10-25:13:16:47.000489
2019-10-25:13:16:48.000399
2019-10-25:13:16:49.000383
2019-10-25:13:16:50.000508