किसी त्रुटि के बाद पाइप लाइन एंड-ऑफ़-फ़ाइल की प्रतीक्षा करें या बंद करें?


12

मैंने इस वीडियो को पाइप शेंनिगन्स पर देखने के बाद निम्नलिखित कमांड की कोशिश की ।

man -k . | dmenu -l 20 | awk '{print $1}' | xargs -r man -Tpdf | zathura -

यह मूल रूप से उपयोगकर्ता के लिए मेन्यूज़ की सूची को उनमें से किसी एक का चयन करने के लिए man -Tpdf %प्रिंट करता है, फिर यह xargs का उपयोग करता है (xargs के इनपुट से मैनपेज git के pdf को प्रिंट करने के लिए प्रिंट) और पीडीएफ रीडर से पीडीएफ पास करने के लिए (ज़थुरा) )।

समस्या यह है कि (जैसा कि आप वीडियो में देख सकते हैं) पीडीएफ रीडर शुरू होता है इससे पहले कि मैं dmenu में एक मैनपेज का चयन करूं। और अगर मैं Esc पर क्लिक करता हूं और कोई भी नहीं चुनता हूं, तो पीडीएफ रीडर अभी भी कोई दस्तावेज़ नहीं दिखा रहा है।

मैं पीडीएफ रीडर (और पाइप श्रृंखला में किसी भी अन्य कमांड) को केवल तभी चला सकता हूं जब उसका इनपुट एंड-ऑफ-फ़ाइल तक पहुंच जाए या जब उसे इनपुट प्राप्त हो जाए? या, वैकल्पिक रूप से, मैं जंजीर आदेशों में से एक के बाद एक गैर-शून्य निकास स्थिति (ताकि यदि dmenu एक विकल्प का चयन नहीं करने के लिए कोई त्रुटि देता है, तो निम्न कमांड नहीं चलाए जाते हैं) को रोकने के लिए एक पाइप श्रृंखला कैसे बना सकता हूं?


1
आप किस खोल का उपयोग कर रहे हैं? क्या यह बैश है?
terdon

मैंने इसे bash, zsh और sh पर आज़माया है। उन सभी का व्यवहार समान था।
सेनिन्हा

2
हां, व्यवहार मानक है, मैंने पूछा कि pipefailकुसालंद के उत्तर में बताए गए विकल्प के कारण कौन सा खोल है ।
टेराडो

जवाबों:


12

मैं पीडीएफ रीडर (और पाइप श्रृंखला में किसी भी अन्य कमांड) को केवल तभी चला सकता हूं जब उसका इनपुट एंड-ऑफ-फ़ाइल तक पहुंच जाए या जब उसे इनपुट प्राप्त हो जाए?

वहाँ है ifne(डेबियन में यह moreutilsपैकेज में है):

ifne निम्न आदेश चलाता है यदि और केवल यदि मानक इनपुट खाली नहीं है।

आपके मामले में:

 | ifne zathura -

उत्तर के लिए धन्यवाद, मुझे यह आदेश नहीं पता था! यह कमांड (और अन्य में moreutils) मूल यूनिक्स में होना चाहिए था और पॉज़िक्स द्वारा निर्दिष्ट किया गया था ... यह एक ऐसा मूल और यूनिक्स-ईश उपकरण है ...
सेनिन्हा

@ सिनिन्हा की सादगी ifneथोड़ी भ्रामक है। यूनिक्स का कोई "पाइप पीचिंग" ऑपरेशन नहीं है, इसलिए ifneवास्तव में निर्भर कमांड को चलाने का निर्णय लेने से पहले कम से कम एक बाइट को पढ़ना चाहिए। इसका मतलब यह है कि यह केवल परीक्षण नहीं कर सकता है और कमांड को निष्पादित कर सकता है, लेकिन एक और पाइप बनाना होगा , आश्रित कमांड को चलाने के लिए एक और प्रक्रिया को कांटा, और स्टड पाइप से डाउनस्ट्रीम पाइप तक पूरी स्ट्रीम को कॉपी करें। यदि "इनपुट खाली" मामला सामान्य नहीं है, ifneतो औसतन, इससे अधिक संसाधनों को आसानी से बचा सकता है।

@ Wumpus.Q। कि एक मिथक है - आप एक पाइप में डेटा है या नहीं यह निर्धारित करने के लिए किसी भी बाइट को पढ़ने के लिए नहीं है। देखें यहाँ । और लिनक्स पर आप वास्तव में कर सकते हैं झांकना एक पाइप से डेटा (यानी इसे हटाने के बिना डेटा पढ़ें)। मैंने यहां "कैनोनिकल" उत्तर की टिप्पणियों में और अधिक उल्लेख किया है, लेकिन उन्हें मॉड्स द्वारा हटा दिया गया क्योंकि उन्हें शायद लगा कि वे तथ्य उत्तर की अजीबता से अलग होने की तरह थे।
मच्छी

6

पीडीएफ फाइलों को खोजने योग्य माना जाता है; किसी भी पीडीएफ दर्शक को पहले ट्रेलर को देखना होगा और वहां से xref टेबल से ऑफ़सेट में कूदना होगा।

चूंकि पाइप साध्य नहीं हैं, zathuraइसलिए एक ओफ़्स्कुलेटिंग ट्रिक का उपयोग कर रहा है, जहां यह एक अस्थायी फ़ाइल के सभी इनपुट की नकल कर रहा है, और फिर उस अस्थायी फ़ाइल का आमतौर पर उपयोग करें। इस तरह की "चतुर" चाल झूठी उम्मीदें पैदा कर रही है और लोगों को यह मानने के लिए प्रेरित कर रही है कि पीडीएफ फाइलें स्ट्रीम करने योग्य हैं।

वैसे भी, zathuraवास्तव में दस्तावेज़ प्रदर्शित करने से पहले ईओएफ के लिए इंतजार करना पड़ता है , आपको उसके लिए कुछ भी करने की ज़रूरत नहीं है:

(sleep 10; cat file.pdf) | zathura -
# will really show the content of file.pdf after 10 seconds

समस्या यह है कि zathuraफ़ाइल के ओके होने पर केवल विंडो खोलने का कोई विकल्प नहीं है, और यदि ऐसा नहीं है तो एक त्रुटि के साथ बाहर निकलें - यह वहीं रहेगा जैसे कि सब कुछ ठीक है:

$ dd if=file.pdf bs=50000 count=1 status=none | zathura -
error: could not open document  # its window still hanging around showing nothing

$ echo $?
0  # really?

यहां तक ​​कि अगर आप आउटपुट को एक अस्थायी फ़ाइल में स्वयं रीडायरेक्ट कर रहे हैं, और केवल तभी चल रहे हैं zathuraजब सब कुछ ठीक था, तो कोई गारंटी नहीं है कि उपयोगकर्ता को एक काली खिड़की के साथ सेवा नहीं दी जाएगी यदि zathuraएक कारण या किसी अन्य के लिए आउटपुट पसंद नहीं है ।


btw,

man -X man

X11 विंडो में एक मैनपेज प्रदर्शित करेगा gxditview, भले ही वह '70;;

और, ज़ाहिर है, आप हमेशा उपयोग कर सकते हैं:

... | xargs xterm -e man

जो, कई अन्य संवर्द्धन के अलावा, आपको खोजों और उचित पाठ चयन में नियमित अभिव्यक्तियों का उपयोग करने देगा।


6

एक पाइपलाइन में सभी कमांड एक ही समय में बहुत अधिक शुरू होता है। यह केवल I / O पाइप पर है जो उन्हें सिंक्रोनाइज़ करता है। इसके अलावा, एक पाइप केवल उतनी ही जानकारी रख सकता है जितना कि पाइप का बफर अनुमति देता है।

इसलिए आप पाइपलाइन के एक चरण को चलाने से बच सकते हैं, क्योंकि

  1. जैसे ही अन्य सभी चरण शुरू होते हैं, और उस चरण में कमांड शुरू हो जाती है
  2. यदि कमांड पाइप के ऊपर आने वाले इनपुट का उपभोग नहीं करता है, तो यह पाइपलाइन के पिछले चरणों को अवरुद्ध करेगा।

इसके बजाय, पाइपलाइन को खत्म करते हुए फ़ाइल को आउटपुट लिखें। फिर उस फ़ाइल का उपयोग करें।

उदाहरण (एक तर्क के रूप में एक समारोह):

myman () {
    tmpfile=$( mktemp )

    if man -k "$1" | dmenu -l 20 | awk '{print $1}' | xargs -r man -Tpdf >"$tmpfile" && [ -s  "$tmpfile" ]
    then
        zathura "$tmpfile"
    fi

    rm -f "$tmpfile"
}

zathuraयदि पाइप लाइन विफल हो जाती है ( xargsगैर-शून्य लौटा हुआ भाग) या जनरेट की गई फ़ाइल खाली है, तो इसके अतिरिक्त यह प्रोग्राम नहीं चलेगा ।

में bashखोल, आप भी सेट करना चाहते हैं सकता है pipefailके साथ खोल विकल्प set -o pipefailपाइपलाइन पाइप लाइन है कि विफल रहता है में पहली आदेश के निकास स्थिति लौटाने के लिए। और आप tmpfileपरिवर्तनशील बनाना चाहेंगे local:

myman () {
    local tmpfile=$( mktemp )

    if [ -o pipefail ]; then
        set -o pipefail
        trap 'set +o pipefail' RETURN
    fi

    if man -k "$1" | dmenu -l 20 | awk '{print $1}' | xargs -r man -Tpdf >"$tmpfile"
    then
        zathura "$tmpfile"
    fi

    rm -f "$tmpfile"
}

यह pipefailफ़ंक्शन की अवधि के लिए विकल्प सेट करता है, अगर यह पहले से सेट नहीं था, और फिर यदि आवश्यक हो तो इसे अनसेट करता है। यह -sआउटपुट फ़ाइल पर परीक्षण से छुटकारा दिलाता है।


1
क्यों rm -f? क्या आप उन मामलों के बारे में सोच रहे हैं जहां पाइप टैम्पाइल की अनुमतियों को बदलता है?
terdon

2
@terdon मैं उन मामलों के बारे में सोच रहा हूँ जहाँ अस्थायी फ़ाइल को समय से पहले हटा दिया जाता है। rm -fयदि फ़ाइल पहले ही हटा दी गई थी (तो शायद zathuraमुझे पता नहीं है) तो त्रुटि नहीं होगी ।
Kusalananda

पहला फ़ंक्शन अपेक्षा के अनुसार काम नहीं करता है: यह ज़थुरा शो को एक काली खिड़की भी बनाएगा, लेकिन अब ज़थुरा पाइपलाइन खत्म होने के बाद चलता है, बजाय पाइप लाइन के साथ चलने के। इसका कारण यह है कि पाइप लाइन xargs की निकास स्थिति लौटाती है, जो 0. है। पाइपलाइन में विफल होने वाली कमांड dmenu है (जो कि 1 का चयन करता है जब मैं कुछ भी नहीं चुनता हूं)। pipefailविकल्प के साथ बैश फ़ंक्शन अपेक्षा के अनुसार काम करता है (और zsh में भी, जिसका विकल्प समान है)।
सेनिन्हा

1
@Seninha मैंने पहले फ़ंक्शन को यह जाँचने दिया था कि क्या जेनरेट की गई फाइल गैर-रिक्त है।
Kusalananda
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.