पाइप श्रृंखला के भीतर jq का उपयोग करना कोई आउटपुट नहीं देता है


12

jqजब आउटपुट पुनर्निर्देशित किया जाता है, तो एक स्पष्ट फिल्टर की आवश्यकता के मुद्दे पर पूरे वेब पर चर्चा की जाती है। अगर मैं jqएक स्पष्ट फिल्टर के उपयोग में है, तो भी मैं आउटपुट को पुनर्निर्देशित करने में असमर्थ हूं , भले ही पाइप श्रृंखला का हिस्सा हो।

विचार करें:

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

जैसा कि अपेक्षित था, jqकमांड से मूल टर्मिनल में आउटपुट है:

1
3

लेकिन अगर मैं jqकमांड के अंत में किसी भी प्रकार के पुनर्निर्देशन या पाइपिंग को जोड़ता हूं , तो आउटपुट चुप हो जाता है:

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

पहले टर्मिनल में कोई आउटपुट नहीं दिखाई देता है और बाहर की जगह खाली है।

मैंने सैकड़ों रूपांतरों की कोशिश की है लेकिन यह एक मायावी मुद्दा है। एकमात्र वर्कअराउंड मैंने पाया है , जैसा कि थ्रू mosquitto_subनेटवर्क और थिंग्स नेटवर्क के माध्यम से खोजा गया था (जो कि मैंने इस मुद्दे को भी खोजा था), एक शेल स्क्रिप्ट में टेल और जेक फ़ंक्शन को लपेटना है :

#!/bin/bash
tail -f $1 | while IFS='' read line; do
echo $line | jq '.f1'
done

फिर:

./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

और निश्चित रूप से पर्याप्त, आउटपुट दिखाई देता है:

1
3

यह jqHomebrew के माध्यम से स्थापित नवीनतम के साथ है :

$ echo $SHELL
/bin/bash
$ jq --version
jq-1.5
$ brew install jq
Warning: jq 1.5_3 is already installed and up-to-date

क्या यह jqपाइप श्रृंखला की मेरी समझ के साथ (काफी हद तक अनिर्दिष्ट) बग है ?


1
एफडब्ल्यूआईडब्ल्यू आपके पास यहां एक काफी (अच्छी तरह से, थोड़ा) अजीब सेटअप है, tail -fएक प्रोग्राम को निरंतर इनपुट प्रदान करने और teeआउटपुट को संसाधित करने के लिए। यदि आपको अभी भी उत्तर की आवश्यकता है, तो मैंने श्रृंखला को सरल बनाने का सुझाव दिया होगा <in.json jq '.f1' >out.jsonताकि आप इसे कम कर सकें कि यह क्या कारण है।
डेविड जेड

बशफेक # 9 भी देखें - बफरिंग क्या है? या, मेरी कमांड लाइन कोई आउटपुट क्यों नहीं देती:tail -f logfile | grep 'foo bar' | awk ...
चार्ल्स डफी

भविष्य के प्रयासों के लिए सभी महान सलाह, धन्यवाद। एफडब्ल्यूआईडब्ल्यू, tailबिट नीचे पाइप को तोड़ने के प्रयास के बारे में आया (पहले कमांड, टी और रीडायरेक्ट को फाइल, टेल कि, पाइप टू नेक्स्ट कमांड, रीडायरेक्ट टू फाइल आदि) और इसे सेक्शन में लगातार रन करें। <हालांकि ध्यान रखें करने के लिए एक अच्छा उपकरण है।
हीथ रेपरटी

जवाबों:


20

jqजब इसके मानक आउटपुट को पाइप किया जाता है, तो आउटपुट से बफर हो जाता है।

यह अनुरोध करने के लिए कि jqहर वस्तु के बाद इसका आउटपुट बफर फ्लश करता है, इसके --unbufferedविकल्प का उपयोग करें , जैसे

tail -f in.txt | jq --unbuffered '.f1' | tee out.txt

से jqमैनुअल:

--unbuffered

प्रत्येक JSON ऑब्जेक्ट के प्रिंट होने के बाद आउटपुट को फ्लश करें (यदि आप एक धीमी डेटा स्रोत को पाइप कर रहे हैं jqऔर jqकहीं और आउटपुट कर रहे हैं)।


इसके अलावा, जिस तरह से मैं इसे डिबग करूंगा, उस आउटपुट बफ़रिंग का पता लगाने के लिए यह मुद्दा था, यह मानते हुए कि मैं केवल यह अनुमान नहीं लगाऊंगा, 'लेट्रेस' और / या 'स्ट्रेस' के तहत 'jq' भाग चलाना होगा। यह स्पष्ट होगा कि इसे C stdio आउटपुट फ़ंक्शन कह रहा है, लेकिन राइट (2) syscall को कॉल नहीं कर रहा है।
SmellyGeek

1
@AnotherSmellyGeek संभवतः, या हमारे यूनियनों पर बराबर अनुरेखण उपयोगिता (ध्यान दें कि ओपी होमब्रे का उपयोग कर रहा है, जिसका अर्थ है कि वे मैकओएस पर हैं, और मैं ओपनबीएसडी पर हूं, जिनमें से किसी के पास भी ये लिनक्स उपकरण नहीं हैं)। एक और संभावना अभी पता चला है कि उत्पादन बफरिंग कुछ निश्चित परिस्थितियों में हो सकता है है :-)
Kusalananda

प्रतिभाशाली। और वास्तव में भविष्य में इसे डीबग करने की सभी सलाह की सराहना करते हैं। बफरिंग मेरे पहले संदेह में से एक था, लेकिन पाइपिंग के लिए अलग व्यवहार मेरे डिबगिंग प्रयासों को झुठला रहा था।
हीथ राफ्टी

6

आप यहां जो देख रहे हैं वह एक्शन में C stdio बफरिंग है। जब तक यह एक निश्चित सीमा (512 बाइट्स, या 4KB या अधिक बड़ा हो सकता है) तक एक बफर पर आउटपुट स्टोर करेगा और फिर एक बार में सभी को भेज देगा।

यह बफ़रिंग स्वचालित रूप से अक्षम हो जाती है यदि स्टडआउट एक टर्मिनल से जुड़ा होता है, लेकिन जब यह एक पाइप से जुड़ा होता है (जैसे कि आपके मामले में), तो यह इस बफरिंग व्यवहार को सक्षम करेगा।

बफ़रिंग को अक्षम / नियंत्रित करने का सामान्य तरीका setvbuf()फ़ंक्शन का उपयोग कर रहा है ( अधिक विवरण के लिए इस उत्तर को देखें), लेकिन इसे jqस्वयं के स्रोत कोड में करने की आवश्यकता होगी , इसलिए शायद आपके लिए कुछ व्यावहारिक नहीं ...

वर्कअराउंड है ... (एक हैक, एक कह सकता है।) "अनबफ़र" नामक एक कार्यक्रम है, जिसे "उम्मीद" के साथ वितरित किया जाता है जो एक छद्म टर्मिनल बना सकता है और इसे एक कार्यक्रम से जोड़ सकता है। इसलिए, भले ही jqअभी भी एक पाइप के लिए लिख रहा हो, यह एक टर्मिनल के लिए लिख रहा है, और बफरिंग प्रभाव निष्क्रिय हो जाएगा।

"अपेक्षा" पैकेज स्थापित करें, जो "अनबफ़र" के साथ आना चाहिए, अगर आपके पास पहले से नहीं है ... उदाहरण के लिए, डेबियन (या उबंटू) पर:

$ sudo apt-get install expect

तब आप इस कमांड का उपयोग कर सकते हैं:

$ tail -f in.txt | unbuffer -p jq '.f1' | tee out.txt

"अनबफ़र" पर कुछ और विवरणों के लिए यह उत्तर भी देखें , और आप यहां एक आदमी पृष्ठ भी पा सकते हैं ।


मुझे पसंद है कि आपने बताया है कि क्यों मनाया गया व्यवहार होता है, लेकिन जैसा कि कुसलानंद ने बताया, jqमूल रूप से उत्पादन को लागू नहीं किया जाता है, इसलिए वर्कअराउंड की कोई आवश्यकता नहीं है।
डेविड जेड

आह बहुत अच्छा! मैंने jqमैन पेज देखना शुरू किया लेकिन थोड़ी देर बाद ऊब गया और अन्य सामान करने चला गया ... अच्छा पता है कि कुछ ऐसा ही है! :-)
फ़िलाब्रांडेन

1
Protip, GNU Coreutils आते हैं stdbuf -o0जो LD_PRELOAD के माध्यम से कोड इंजेक्ट करेंगे और setvbuf()आपके लिए मैजिक कॉल करेंगे। यह macOS पर काम करता है या नहीं, मुझे यकीन नहीं है।
user1686

1
जबकि expectमैकोस पर पूर्व-स्थापित है, unbufferनहीं है। हालाँकि, यह होमब्रे पैकेज का हिस्सा है, इसलिए मैकोस पर, brew install expectकरेगा।
हीथ रेपरटी
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.