Saya ingin menambahkan cap waktu ke setiap baris output dari sebuah perintah. Sebagai contoh:
foo
bar
baz
akan menjadi
[2011-12-13 12:20:38] foo
[2011-12-13 12:21:32] bar
[2011-12-13 12:22:20] baz
... di mana waktu yang diawali adalah waktu di mana garis itu dicetak. Bagaimana saya bisa mencapai ini?
Jawaban:
moreutils termasuk
ts
yang melakukan ini dengan cukup baik:command | ts '[%Y-%m-%d %H:%M:%S]'
Ini menghilangkan kebutuhan untuk loop juga, setiap baris output akan memiliki timestamp yang diletakkan di atasnya.
Anda ingin tahu kapan server itu muncul kembali Anda me-restart? Jalankan saja
ping | ts
, masalah terpecahkan: D.sumber
tail -f /tmp/script.results.txt | ts
ssh -v 127.0.0.1 2>&1 | ts
-s
berguna. Ketika itu menampilkan runtime dari perintah. Saya pribadi suka menggunakan keduanyats
dants -s
pada saat yang sama. Terlihat seperti ini:command | ts -s '(%H:%M:%.S)]' | ts '[%Y-%m-%d %H:%M:%S'
. Ini menambahkan baris log seperti ini:[2018-12-04 08:31:00 (00:26:28.267126)] Hai <3
Pertama, jika Anda mengharapkan cap waktu ini benar-benar mewakili suatu peristiwa, ingatlah bahwa karena banyak program melakukan buffering garis (beberapa lebih agresif daripada yang lain), penting untuk menganggap ini sedekat waktu dengan garis asli akan memiliki telah dicetak daripada cap waktu tindakan yang sedang berlangsung.
Anda mungkin juga ingin memeriksa apakah perintah Anda belum memiliki fitur bawaan yang didedikasikan untuk melakukan ini. Sebagai contoh,
ping -D
ada dalam beberapaping
versi, dan mencetak waktu sejak zaman Unix sebelum setiap baris. Namun, jika perintah Anda tidak mengandung metode sendiri, ada beberapa metode dan alat yang dapat digunakan, antara lain:Shell POSIX
Ingatlah bahwa karena banyak shell menyimpan string mereka secara internal sebagai cstring, jika input berisi karakter null (
\0
), ini dapat menyebabkan garis berakhir sebelum waktunya.GNU awk
Perl
Python
Rubi
sumber
stdbuf -o 0
, tetapi jika program secara manual menangani buffering outputnya, itu tidak akan membantu (kecuali ada opsi untuk menonaktifkan / mengurangi ukuran buffer output).python -u
... for x in sys.stdin
iterates melalui baris tanpa buffering mereka semua ke dalam memori terlebih dahulu.Untuk pengukuran delta baris demi baris, coba gnomon .
sumber
ts
saat menggunakan proses langsung. Sementarats
lebih cocok untuk proses non-interaktif.Posting Ryan memang memberikan ide yang menarik, namun gagal dalam beberapa hal. Saat menguji dengan
tail -f /var/log/syslog | xargs -L 1 echo $(date +'[%Y-%m-%d %H:%M:%S]') $1
, saya perhatikan bahwa stempel waktu tetap sama bahkan jikastdout
datang kemudian dengan perbedaan dalam detik terpisah. Pertimbangkan output ini:Solusi yang saya usulkan serupa, namun memberikan cap waktu yang tepat dan menggunakan yang agak lebih portabel
printf
daripadaecho
Mengapa
bash -c '...' bash
? Karena karena-c
opsi, argumen pertama ditugaskan$0
dan tidak akan muncul di output. Lihat halaman buku panduan shell Anda untuk deskripsi yang tepat-c
Menguji solusi ini dengan
tail -f /var/log/syslog
dan (karena Anda mungkin bisa menebak) memutuskan dan menghubungkan kembali ke wifi saya, telah menunjukkan cap waktu yang tepat yang disediakan oleh keduanyadate
dansyslog
pesanBash dapat digantikan oleh shell seperti bourne, dapat dilakukan dengan salah satu ,
ksh
ataudash
setidaknya mereka yang memiliki-c
opsi.Masalah potensial:
Solusinya memerlukan memiliki
xargs
, yang tersedia pada sistem yang sesuai dengan POSIX, sehingga sebagian besar sistem seperti Unix harus dicakup. Jelas tidak akan berfungsi jika sistem Anda tidak memenuhi syarat POSIX atau tidakGNU findutils
sumber
Saya lebih suka berkomentar di atas tetapi saya tidak bisa, secara reputasi. Bagaimanapun, sampel Perl di atas dapat di-unbuffered sebagai berikut:
'$ |' Pertama unbuffers STDOUT. Yang kedua menetapkan stderr sebagai saluran keluaran default saat ini dan melepaskannya. Karena pilih mengembalikan pengaturan asli $ |, dengan membungkus pilih di dalam pilih, kami juga mengatur ulang $ | ke standarnya, STDOUT.
Dan ya, Anda dapat memotong dan menempelkan apa adanya. Saya multi-baris untuk keterbacaan.
Dan jika Anda benar-benar ingin mendapatkan yang tepat (dan Anda memiliki Waktu :: Karyawan yang diinstal):
sumber
Sebagian besar jawaban menyarankan untuk digunakan
date
, tetapi cukup lambat. Jika versi bash Anda lebih besar dari 4.2.0 lebih baik digunakanprintf
, itu bash builtin. Jika Anda perlu mendukung versi bash lawas, Anda dapat membuatlog
fungsi bergantung pada versi bash:Lihat perbedaan kecepatan:
UPD: daripada
$(date +"${TIMESTAMP_FORMAT}")
lebih baik menggunakan$(exec date +"${TIMESTAMP_FORMAT}")
atau bahkan$(exec -c date +"${TIMESTAMP_FORMAT}")
mempercepat eksekusi.sumber
Anda dapat melakukan ini dengan
date
danxargs
:Penjelasan:
xargs -L 1
memberi tahu xargs untuk menjalankan perintah proses untuk setiap 1 baris input, dan ia meneruskan di baris pertama saat melakukannya.echo `date +'[%Y-%m-%d %H:%M:%S]'` $1
pada dasarnya gema tanggal dengan argumen input di akhir itusumber
$1
. Itu bukan gaya yang baik. Selalu kutip variabelnya. Selain itu, Anda menggunakanecho
, yang tidak portabel. Tidak apa-apa, tetapi mungkin tidak berfungsi dengan baik pada beberapa sistem.date
mengevaluasi ulang setiap baris, atau apakah itu cukup sia-sia?