मैं दो कमांड के आउटपुट को कैसे अलग करूं?


165

मैंने दो समान निर्देशिकाओं की सामग्री की तुलना करने के लिए सबसे सरल तरीका सोचा था

diff `ls old` `ls new`

लेकिन मैं देखता हूं कि यह काम क्यों नहीं करता है; diffकमांड लाइन पर फ़ाइलों की एक बड़ी लंबी सूची सौंपी जा रही है, बल्कि दो धाराओं जैसे मुझे उम्मीद थी। सीधे अंतर करने के लिए मैं दो आउटपुट कैसे पास करूं?


जवाबों:


246

कमांड प्रतिस्थापन `…`कमांड लाइन में कमांड के आउटपुट को प्रतिस्थापित करता है, इसलिए diffदोनों निर्देशिकाओं में फाइलों की सूची को तर्क के रूप में देखता है। आप जो चाहते हैं वह diffइसकी कमांड लाइन पर दो फ़ाइल नाम देखने के लिए है, और इन फ़ाइलों की सामग्री निर्देशिका लिस्टिंग है। यही प्रक्रिया प्रतिस्थापन करती है।

diff <(ls old) <(ls new)

दलीलें diffदेखने के लिए जैसी लगेंगी /dev/fd/3और /dev/fd/4: वे बैश द्वारा बनाए गए दो पाइपों के अनुरूप फाइल डिस्क्रिप्टर हैं। जब diffइन फ़ाइलों को खोलता है, यह प्रत्येक पाइप के पढ़ने के पक्ष से कनेक्ट हो जाएगा। प्रत्येक पाइप का राइट साइड lsकमांड से जुड़ा होता है ।


49
echo <(echo) <(echo)कभी नहीं सोचा था कि यह इतना दिलचस्प हो सकता है: डी
कुंभ राशि का पावर

3
प्रक्रिया प्रतिस्थापन सभी गोले द्वारा समर्थित नहीं है , लेकिन पाइप पुनर्निर्देशन एक स्वच्छ समाधान है
इरफान ४३४

1
बस यह उल्लेख करने के लिए कि पार्सिंग ls की सिफारिश नहीं की जाती है unix.stackexchange.com/questions/128985/why-not-parse-ls
काटू

@ केतु के साथ समस्या lsयह है कि यह फ़ाइल नाम का प्रबंधन करता है। इसकी आउटपुट पार्सिंग नाजुक है (यह "अजीब" फ़ाइल नामों के साथ काम नहीं करता है)। दो निर्देशिका लिस्टिंग की तुलना करने के लिए, यह तब तक ठीक है जब तक आउटपुट अस्पष्ट है। मनमाने फ़ाइल नामों के साथ, इसके लिए एक विकल्प की आवश्यकता होगी --quoting-style=escape
गिल्स

1
@will <(…)एक पाइप बनाता है। ऐसा लगता है कि मेल्ड पाइप के साथ काम नहीं करता है, इसलिए आप उपयोग नहीं कर सकते <(…)। Zsh में, आप <(…)द्वारा प्रतिस्थापित कर सकते हैं =(…)और यह काम करेगा क्योंकि =(…)एक अस्थायी फ़ाइल में मध्यवर्ती आउटपुट डालता है। बाश में मुझे नहीं लगता कि कोई सुविधाजनक वाक्यविन्यास है, आपको अस्थायी फ़ाइलों को स्वयं प्रबंधित करना होगा।
गिले

3

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

तो तीन विकल्प हैं:

  1. कमांड प्रतिस्थापन: $(...)
  2. प्रक्रिया प्रतिस्थापन: <(...)
  3. zsh-Flavoured प्रक्रिया प्रतिस्थापन: =(...)

zsh फ्लेवर्ड प्रोसेस सबस्क्राइबेशन, # 3, बहुत उपयोगी है और इसका उपयोग इस तरह किया जा सकता है कि एक अलग टूल का उपयोग करके दो कमांड्स के आउटपुट की तुलना करें, उदाहरण के लिए तुलना करें:

bcomp  =(ulimit -Sa | sort) =(ulimit -Ha | sort)

तुलना से परे, ध्यान दें कि तुलना शुरू करने और उसके पूरा होने का इंतजारbcomp करने के bcompareबाद से आपको ऊपर (इसके बजाय ) का उपयोग करना चाहिए । यदि आप उपयोग करते हैं , तो वह तुलना शुरू करता है और तुरंत बाहर निकल जाता है जिसके कारण कमांड के आउटपुट को स्टोर करने के लिए बनाई गई अस्थायी फाइलें गायब हो जाती हैं।bcompbcompare

यहां पढ़ें: http://zsh.sourceforge.net/Intro/intro_7.html

यह भी ध्यान दें:

ध्यान दें कि शेल एक अस्थायी फ़ाइल बनाता है, और कमांड समाप्त होने पर इसे हटा देता है।

और निम्नलिखित जो कि zsh द्वारा समर्थित प्रक्रिया प्रतिस्थापन के दो प्रकारों के बीच का अंतर है (अर्थात # 2 और # 3):

यदि आप zsh का मैन पेज पढ़ते हैं, तो आप देख सकते हैं कि <(...) प्रक्रिया प्रतिस्थापन का दूसरा रूप है जो = (...) के समान है। दोनों के बीच एक महत्वपूर्ण अंतर है। <(...) मामले में, शेल एक फ़ाइल के बजाय एक नामित पाइप (FIFO) बनाता है। यह बेहतर है, क्योंकि यह फ़ाइल सिस्टम को नहीं भरता है; लेकिन यह सभी मामलों में काम नहीं करता है। वास्तव में, यदि हमने ऊपर के उदाहरणों में <(...) के साथ = (...) को प्रतिस्थापित किया होता, तो उन सभी को fgrep -f <(...) को छोड़कर काम करना बंद कर दिया होता। आप एक पाइप को संपादित नहीं कर सकते हैं, या इसे मेल फ़ोल्डर के रूप में खोल सकते हैं; हालाँकि, fgrep को पाइप से शब्दों की सूची पढ़ने में कोई समस्या नहीं है। आप आश्चर्यचकित हो सकते हैं कि अलग क्यों <(foo) बार काम नहीं करता है, क्योंकि foo | अलग - बार काम करता है; इसका कारण यह है कि यदि कोई यह तर्क देता है कि यह एक अस्थायी फ़ाइल है, तो यह एक अस्थायी फ़ाइल बनाता है - और फिर इसके मानक इनपुट को अस्थायी फ़ाइल में कॉपी कर देता है।

संदर्भ: https://unix.stackexchange.com/questions/393349/difference-between-subshells-and-process-substeration


2
$(...)प्रतिस्थापन की प्रक्रिया नहीं है, यह कमांड प्रतिस्थापन है। <(...)प्रक्रिया प्रतिस्थापन है। इसलिए उद्धृत मार्ग का उल्लेख नहीं है $(...)
मुरु

2

मछली का खोल

फिश शेल में आपको सोब में पाइप करना होता है । यहाँ बियॉन्ड की तुलना में हरोकू और डॉक्यू कॉन्फिग तुलना का एक उदाहरण दिया गया है :

bcompare (ssh me@myapp.pl dokku config myapp | sort | psub) (heroku config -a myapp | sort | psub)

1
एक अन्य ग्राफिकल डिफ टूल है meldजो ओपन सोर्स है और उबंटू और ईपीईएल रिपॉजिटरी में उपलब्ध है। meldmerge.org
फ़िफी

0

मैं अक्सर स्वीकृत उत्तर में वर्णित तकनीक का उपयोग करता हूं:

diff <(ls old) <(ls new)

लेकिन मुझे लगता है कि मैं आमतौर पर ऊपर के उदाहरण की तुलना में बहुत अधिक जटिल आदेशों के साथ इसका उपयोग करता हूं। ऐसे मामलों में यह डिफरेंट कमांड को क्राफ्ट करने के लिए कष्टप्रद हो सकता है। मैं कुछ समाधानों के साथ आया हूं जो अन्य उपयोगी हो सकते हैं।

मुझे लगता है कि अलग-अलग चलने से पहले मैं संबंधित आदेशों को आज़माने का 99% समय पाता हूं। नतीजतन, जो आदेश मैं अलग करना चाहता हूं वे मेरे इतिहास में वहीं हैं ... उनका उपयोग क्यों नहीं किया जाता है?

मैं पिछले दो आदेशों को निष्पादित करने के लिए फिक्स कमांड (fc) बैश बिलिन का उपयोग करता हूं:

$ echo A
A
$ echo B
B
$ diff --color <( $(fc -ln -1 -1) ) <( $(fc -ln -2 -2 ) )
1c1
< B
---
> A

एफसी झंडे हैं:

-n : कोई संख्या नहीं। लिस्टिंग करते समय यह कमांड नंबरों को दबा देता है।

-l : लिस्टिंग: कमांड मानक आउटपुट पर सूचीबद्ध हैं।

-1 -1इतिहास में शुरू और अंत का हवाला देते हुए, इस मामले में इसकी अंतिम कमांड से अंतिम कमांड तक जो सिर्फ आखिरी कमांड देता है।

अंत में हम इसे $()सब-कमांड में कमांड निष्पादित करने के लिए लपेटते हैं ।

जाहिर है कि यह टाइप करने के लिए थोड़ा दर्द है तो हम एक उपनाम बना सकते हैं:

alias dl='diff --color <( $(fc -ln -1 -1) ) <( $(fc -ln -2 -2 ) )'

या हम एक समारोह बना सकते हैं:

dl() {
    if [[ -z "$1" ]]; then
        first="1"
    else
        first="$1"
    fi
    if [[ -z "$2" ]]; then
        last="2"
    else
        last="$2"
    fi
    # shellcheck disable=SC2091
    diff --color <( $(fc -ln "-$first" "-$first") ) <( $(fc -ln "-$last" "-$last") )
}

जो उपयोग करने के लिए इतिहास लाइनों को निर्दिष्ट करने का समर्थन करता है। दोनों का उपयोग करने के बाद मुझे लगता है कि उपनाम मुझे पसंद है।

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