Masalah jq
memerlukan filter eksplisit ketika output diarahkan kembali dibahas di seluruh web. Tapi saya tidak dapat mengarahkan output jika jq
merupakan bagian dari rantai pipa, bahkan ketika filter eksplisit sedang digunakan.
Mempertimbangkan:
touch in.txt
tail -f in.txt | jq '.f1'
# in a different terminal:
echo '{"f1":1,"f2":2}' >> in.txt
echo '{"f1":3,"f2":2}' >> in.txt
Seperti yang diharapkan, output di terminal asli dari jq
perintah adalah:
1
3
Tetapi jika saya menambahkan segala jenis pengalihan atau pemipaan ke akhir jq
perintah, hasilnya menjadi sunyi:
rm in.txt
touch in.txt
tail -f in.txt | jq '.f1' | tee out.txt
# in a different terminal:
echo '{"f1":1,"f2":2}' >> in.txt
echo '{"f1":3,"f2":2}' >> in.txt
Tidak ada output yang muncul di terminal pertama dan out.txt kosong.
Saya sudah mencoba ratusan variasi tetapi ini masalah yang sulit dipahami. Satu-satunya solusi yang saya temukan , seperti yang ditemukan melalui mosquitto_sub
dan The Things Network (yang merupakan tempat saya juga menemukan masalah), adalah untuk membungkus fungsi ekor dan jq dalam skrip shell:
#!/bin/bash
tail -f $1 | while IFS='' read line; do
echo $line | jq '.f1'
done
Kemudian:
./tail_and_jq.sh | tee out.txt
# in a different terminal:
echo '{"f1":1,"f2":2}' >> in.txt
echo '{"f1":3,"f2":2}' >> in.txt
Dan benar saja, output muncul:
1
3
Ini dengan yang terbaru jq
diinstal melalui Homebrew:
$ echo $SHELL
/bin/bash
$ jq --version
jq-1.5
$ brew install jq
Warning: jq 1.5_3 is already installed and up-to-date
Apakah ini bug (sebagian besar tidak berdokumen) di jq
atau dengan pemahaman saya tentang rantai pipa?
sumber
tail -f
untuk memberikan input terus menerus ke suatu program dantee
untuk memproses output. Jika Anda masih membutuhkan jawaban, saya akan menyarankan untuk menyederhanakan rantai<in.json jq '.f1' >out.json
sehingga Anda dapat mempersempit apa yang menyebabkannya.tail -f logfile | grep 'foo bar' | awk ...
tail
bit muncul dari upaya untuk memecah pipa (jalankan perintah pertama, tee dan redirect ke file, ekor itu, pipa ke perintah berikutnya, redirect ke file, dll) dan jalankan terus menerus dalam beberapa bagian. Ini<
adalah alat yang baik untuk diingat.Jawaban:
Output dari
jq
buffered ketika output standarnya disalurkan.Untuk meminta yang
jq
mem-flush buffer outputnya setelah setiap objek, gunakan--unbuffered
opsinya, misDari
jq
manual:sumber
Apa yang Anda lihat di sini adalah buffering C stdio dalam aksi. Ini akan menyimpan output pada buffer hingga mencapai batas tertentu (mungkin 512 byte, atau 4KB atau lebih besar) dan kemudian mengirimkannya sekaligus.
Buffer ini dinonaktifkan secara otomatis jika stdout terhubung ke terminal, tetapi ketika terhubung ke pipa (seperti dalam kasus Anda), buffering ini akan mengaktifkan perilaku buffering ini.
Cara biasa untuk menonaktifkan / mengontrol buffering adalah menggunakan
setvbuf()
fungsi (lihat jawaban ini untuk lebih jelasnya), tetapi itu perlu dilakukan dalam kode sumbernyajq
sendiri, jadi mungkin bukan sesuatu yang praktis untuk Anda ...Ada solusinya ... (Retas, bisa dikatakan.) Ada program yang disebut "unbuffer", yang didistribusikan dengan "harapkan" yang dapat membuat terminal pseudo dan menghubungkannya ke program. Jadi, meskipun
jq
masih akan menulis ke pipa, itu akan berpikir itu menulis ke terminal, dan efek buffering akan dinonaktifkan.Instal paket "expect", yang seharusnya datang dengan "unbuffer", jika Anda belum memilikinya ... Misalnya, di Debian (atau Ubuntu):
Kemudian Anda dapat menggunakan perintah ini:
Lihat juga jawaban ini untuk beberapa detail lebih lanjut tentang "unbuffer", dan Anda dapat menemukan halaman manual di sini juga .
sumber
jq
secara alami mengimplementasikan output yang tidak terganggu sehingga tidak perlu untuk menyelesaikannya.jq
halaman manual tetapi bosan setelah beberapa saat dan pergi untuk melakukan hal-hal lain ... Senang mengetahui ada sesuatu seperti itu! :-)stdbuf -o0
yang akan menyuntikkan kode melalui LD_PRELOAD dan melakukansetvbuf()
panggilan ajaib untuk Anda. Apakah itu berfungsi pada macOS, saya tidak yakin.expect
sudah diinstal pada Macos,unbuffer
tidak. Namun itu adalah bagian dari paket Homebrew, jadi pada macro,brew install expect
akan dilakukan.