मैं कई आदेशों को कैसे भेज सकता हूं?


186

कुछ कमांड हैं जो इनपुट पर फ़िल्टर या कार्य करते हैं, और फिर इसे आउटपुट के रूप में पास करते हैं, मुझे लगता है कि आमतौर पर stdout- - लेकिन कुछ कमांड बस इसे ले लेंगे stdinऔर इसके साथ जो भी करेंगे, और आउटपुट कुछ भी नहीं करेंगे।

मैं ओएस एक्स से सबसे अधिक परिचित हूं और इसलिए दो हैं जो तुरंत दिमाग में आते हैं pbcopyऔर pbpaste- जो सिस्टम क्लिपबोर्ड तक पहुंचने के साधन हैं।

किसी भी तरह, मुझे पता है कि अगर मैं स्टडआउट लेना चाहता हूं और आउटपुट को दोनों stdoutऔर एक फाइल पर जाने के लिए थूकना चाहता हूं तो मैं teeकमांड का उपयोग कर सकता हूं । और मुझे इसके बारे में थोड़ा पता है xargs, लेकिन मुझे नहीं लगता कि मैं यही देख रहा हूं।

मैं जानना चाहता हूं कि मैं stdoutदो (या अधिक) कमांड के बीच जाने के लिए कैसे विभाजित हो सकता हूं । उदाहरण के लिए:

cat file.txt | stdout-split -c1 pbcopy -c2 grep -i errors

उस एक से बेहतर उदाहरण शायद है, लेकिन मैं वास्तव में यह जानने में दिलचस्पी रखता हूं कि मैं एक कमांड को कैसे भेज सकता हूं जो इसे रिले नहीं करता है और stdout"म्यूट" होने से बचाते हुए - मैं catकिसी फाइल के बारे में नहीं पूछ रहा हूं और grepइसका एक हिस्सा और इसे क्लिपबोर्ड पर कॉपी करें - विशिष्ट कमांड यह महत्वपूर्ण नहीं हैं।

इसके अलावा - मैं यह नहीं पूछ रहा हूं कि इसे किसी फाइल में कैसे भेजा जाए stdout- और यह एक "डुप्लिकेट" सवाल (खेद) हो सकता है, लेकिन मैंने कुछ तलाश किया और केवल वही खोज सकता हूं जो पूछ रहे थे कि स्टडआउट और फाइल के बीच विभाजन कैसे करें - और उन सवालों के जवाब लग रहे थे tee, जो मुझे नहीं लगता कि मेरे लिए काम करेगा।

अंत में, आप पूछ सकते हैं "पाइप श्रृंखला में बस आखिरी चीज को क्यों नहीं बनाते हैं?" और मेरी प्रतिक्रिया 1 है) क्या होगा यदि मैं इसका उपयोग करना चाहता हूं और अभी भी कंसोल में आउटपुट देखता हूं? 2) क्या होगा अगर मैं दो कमांड का उपयोग करना चाहता हूं जो stdoutइनपुट की प्रक्रिया के बाद आउटपुट नहीं करते हैं ?

ओह, और एक और बात - मुझे एहसास है कि मैं उपयोग कर सकता हूं teeऔर एक नामित पाइप ( mkfifo) है, लेकिन मैं एक तरह से उम्मीद कर रहा था कि यह बिना किसी पूर्व सेटअप के, इनलाइन तरीके से किया जा सकता है :)


के संभावित डुप्लिकेट unix.stackexchange.com/questions/26964/...
निखिल Mulley

जवाबों:


239

आप इसके लिए teeप्रतिस्थापन का उपयोग और प्रक्रिया कर सकते हैं :

cat file.txt | tee >(pbcopy) | grep errors

इस सब के उत्पादन भेज देंगे cat file.txtकरने के लिए pbcopy, और आप केवल का परिणाम मिल जाएगा grepअपने कंसोल पर।

आप teeभाग में कई प्रक्रियाएँ डाल सकते हैं :

cat file.txt | tee >(pbcopy) >(do_stuff) >(do_more_stuff) | grep errors

21
के साथ एक चिंता का विषय नहीं है pbcopy, लेकिन सामान्य रूप से ध्यान देने योग्य है: जो कुछ भी प्रक्रिया प्रतिस्थापन आउटपुट मूल इनपुट के बाद, अगले पाइप खंड द्वारा भी देखा जाता है; उदाहरण: seq 3 | tee >(cat -n) | cat -e( cat -nइनपुट लाइनों को cat -eबताता है $, के साथ newlines के निशान ; आप देखेंगे कि cat -eमूल इनपुट (पहले) और (तब) से आउटपुट दोनों पर लागू होता है cat -nकई प्रक्रिया प्रतिस्थापनों से आउटपुट गैर-नियतात्मक क्रम में आ जाएगा।
mklement0

49
में >(ही काम करता है bash। यदि आप कोशिश करते हैं कि उदाहरण के लिए shयह काम नहीं करेगा। यह नोटिस करना महत्वपूर्ण है।
AAlvz

10
@ एवल्ज़: अच्छी बात: प्रक्रिया प्रतिस्थापन एक पॉसिक्स सुविधा नहीं है; dash, जो shउबंटू के रूप में कार्य करता है, वह इसका समर्थन नहीं करता है, और यहां तक ​​कि बैश खुद को इस सुविधा को निष्क्रिय कर देता है जब इसे लागू किया जाता है shया जब set -o posixप्रभाव होता है। हालांकि, यह सिर्फ बैश नहीं है जो प्रक्रिया प्रतिस्थापन का समर्थन करता है: kshऔर zshउनका समर्थन भी करें (दूसरों के बारे में निश्चित नहीं)।
mklement0

2
@ mklement0 जो सत्य प्रतीत नहीं होता है। Zsh (Ubuntu 14.04) पर आपकी लाइन प्रिंट करती है: 1 1 2 2 3 3 1 $ 2 $ 3 $ $ जो दुःखद है, क्योंकि मैं वास्तव में कार्यक्षमता को वैसा ही बनाना चाहता था जैसा आप कहते हैं।
अकटौ

2
@ अकाटौ: वास्तव में, मेरा नमूना कमांड केवल वर्णित के रूप में काम करता है - bashऔर जाहिर तौर पर पाइपलाइन के माध्यम से आउटपुट प्रक्रिया प्रतिस्थापन से आउटपुट नहीं भेजता (यकीनन, यह बेहतर है , क्योंकि यह अगले पाइपलाइन सेगमेंट को भेजा गया प्रदूषित नहीं करता है - हालांकि यह अभी भी प्रिंट करता है )। में सभी उत्पादन आदेश उम्मीद के मुताबिक नहीं होगा, एक तरीके से कि केवल बार बार या बड़े के साथ आ सकता है - उल्लेख गोले, तथापि, यह आम तौर पर एक भी पाइप लाइन है, जिसमें नियमित stdout उत्पादन और प्रक्रिया प्रतिस्थापन से उत्पादन मिलाया जाता है के लिए एक अच्छा विचार है आउटपुट डेटा सेट। kshzsh
mklement0

124

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

प्रक्रिया प्रतिस्थापन

यदि आपका खोल ksh93, bash या zsh है, तो आप प्रक्रिया प्रतिस्थापन का उपयोग कर सकते हैं। यह एक कमांड को एक पाइप पास करने का एक तरीका है जो फ़ाइल नाम की अपेक्षा करता है। शेल पाइप बनाता है और /dev/fd/3कमांड की तरह एक फ़ाइल नाम से गुजरता है । नंबर फ़ाइल डिस्क्रिप्टर है जो पाइप से जुड़ा है। कुछ यूनिक्स वेरिएंट समर्थन नहीं करते हैं /dev/fd; इन पर, इसके बजाय एक नामित पाइप का उपयोग किया जाता है (नीचे देखें)।

tee >(command1) >(command2) | command3

फ़ाइल विवरणक

किसी भी POSIX शेल में, आप स्पष्ट रूप से कई फ़ाइल डिस्क्रिप्टर का उपयोग कर सकते हैं । इसके लिए एक यूनिक्स संस्करण की आवश्यकता होती है /dev/fd, जो समर्थन करता है , लेकिन teeनाम से निर्दिष्ट आउटपुट में से एक होना चाहिए।

{ { { tee /dev/fd/3 /dev/fd/4 | command1 >&9;
    } 3>&1 | command2 >&9;
  } 4>&1 | command3 >&9;
} 9>&1

नाम दिया गया पाइप

सबसे बुनियादी और पोर्टेबल विधि नामित पाइप का उपयोग करना है । नकारात्मक पक्ष यह है कि आपको एक योग्य निर्देशिका खोजने, पाइप बनाने और बाद में साफ करने की आवश्यकता है।

tmp_dir=$(mktemp -d)
mkfifo "$tmp_dir/f1" "$tmp_dir/f2"
command1 <"$tmp_dir/f1" & pid1=$!
command2 <"$tmp_dir/f2" & pid2=$!
tee "$tmp_dir/f1" "$tmp_dir/f2" | command3
rm -rf "$tmp_dir"
wait $pid1 $pid2

10
उन लोगों के लिए दो वैकल्पिक संस्करण प्रदान करने के लिए बहुत बहुत धन्यवाद जो बैश या एक निश्चित ksh पर भरोसा नहीं करना चाहते हैं।
trr

tee "$tmp_dir/f1" "$tmp_dir/f2" | command3निश्चित रूप से होना चाहिए command3 | tee "$tmp_dir/f1" "$tmp_dir/f2", के रूप में आप command3करने के लिए पाइप के stdout चाहते हैं tee, नहीं? मैंने आपके संस्करण का परीक्षण किया dashऔर teeइनपुट के लिए अनिश्चित काल तक प्रतीक्षा कर रहा था, लेकिन स्विच करने से अपेक्षित परिणाम प्राप्त हुआ।
एड्रियन गुंटर

1
@ AdrianGünter नहीं। सभी तीन उदाहरण मानक इनपुट से डेटा पढ़ते हैं और प्रत्येक को भेजते हैं command, command2और command3
गिल्स

@ मैं देख रहा हूं, मैंने इरादे को गलत बताया और गलत तरीके से स्निपेट का उपयोग करने की कोशिश की। स्पष्टीकरण के लिए धन्यवाद!
एड्रियन गुंटर

यदि आपके पास उपयोग किए गए शेल पर कोई नियंत्रण नहीं है, लेकिन आप स्पष्ट रूप से बैश का उपयोग कर सकते हैं, तो आप कर सकते हैं <command> | bash -c 'tee >(command1) >(command2) | command3'। इसने मेरे मामले में मदद की।
जीसी ५

16

बस प्रक्रिया प्रतिस्थापन के साथ खेलते हैं।

mycommand_exec |tee >(grep ook > ook.txt) >(grep eek > eek.txt)

grepदो बायनेरिज़ हैं जो mycommand_execउनकी प्रक्रिया विशिष्ट इनपुट के समान आउटपुट हैं ।


16

यदि आप उपयोग कर रहे हैं zshतो आप MULTIOSसुविधा की शक्ति का लाभ उठा सकते हैं , अर्थात teeपूरी तरह से कमांड से छुटकारा पा सकते हैं :

uname >file1 >file2

सिर्फ unameदो अलग-अलग फ़ाइलों के आउटपुट को लिखेंगे : file1और file2, किसके बराबर हैuname | tee file1 >file2

इसी तरह मानक आदानों का पुनर्निर्देशन

wc -l <file1 <file2

के बराबर है cat file1 file2 | wc -l(कृपया ध्यान दें कि यह समान नहीं है wc -l file1 file2, बाद में प्रत्येक फ़ाइल में अलग से लाइनों की संख्या की गणना करता है)।

बेशक, आप MULTIOSफ़ाइलों को नहीं बल्कि अन्य प्रक्रियाओं को भी आउटपुट प्रतिस्थापन का उपयोग करके अप्रत्यक्ष रूप से आउटपुट का उपयोग कर सकते हैं , जैसे:

echo abc > >(grep -o a) > >(tr b x) > >(sed 's/c/y/')

3
जानकार अच्छा लगा। MULTIOSएक ऐसा विकल्प है जो डिफ़ॉल्ट रूप से चालू है (और इसे बंद किया जा सकता है unsetopt MULTIOS)।
mklement0

6

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

उदाहरण के लिए, निम्न स्क्रिप्ट ऐसा कर सकती है:

#!/bin/sh

temp=$( mktemp )
cat /dev/stdin > "$temp"

for arg
do
    eval "$arg" < "$temp"
done
rm "$temp"

शेल के /bin/shरूप में Ubuntu 16.04 पर टेस्ट रन dash:

$ cat /etc/passwd | ./multiple_pipes.sh  'wc -l'  'grep "root"'                                                          
48
root:x:0:0:root:/root:/bin/bash

5

कमांड STDOUTको एक वैरिएबल पर कैप्चर करें और इसे जितनी बार चाहें उतनी बार उपयोग करें:

commandoutput="$(command-to-run)"
echo "$commandoutput" | grep -i errors
echo "$commandoutput" | pbcopy

यदि आपको STDERRभी पकड़ने की आवश्यकता है, तो 2>&1कमांड के अंत में उपयोग करें , जैसे:

commandoutput="$(command-to-run 2>&1)"

3
चर कहाँ संग्रहीत हैं? यदि आप एक बड़ी फ़ाइल या उस चीज़ के साथ काम कर रहे थे, तो क्या यह बहुत अधिक मेमोरी नहीं बढ़ाएगा? क्या चर आकार में सीमित हैं?
cwd

1
क्या होगा अगर $ कमांडआउट बहुत बड़ा है ?, पाइप और प्रक्रिया प्रतिस्थापन का उपयोग करने के लिए बेहतर है।
निखिल मुल्ले

4
जाहिर है कि यह समाधान तभी संभव है जब आप जानते हैं कि आउटपुट का आकार आसानी से मेमोरी में फिट होगा, और आप इस पर अगला कमांड चलाने से पहले पूरे आउटपुट को बफरिंग के साथ ओके करेंगे। पाइप्स इन दो समस्याओं को हल करते हैं मनमाना लंबाई डेटा और वास्तविक समय में इसे रिसीवर को स्ट्रीमिंग करने की अनुमति देता है क्योंकि यह उत्पन्न होता है।
trr

2
यह एक अच्छा समाधान है यदि आपके पास छोटा आउटपुट है, और आप जानते हैं कि आउटपुट टेक्स्ट होगा और बाइनरी नहीं होगा। (शेल चर अक्सर बाइनरी सुरक्षित नहीं होते हैं)
Rucent88

1
मैं बाइनरी डेटा के साथ काम करने के लिए इसे प्राप्त नहीं कर सकता। मुझे लगता है कि यह गूंज बाइट्स या कुछ अन्य नॉनचैकर डेटा की व्याख्या करने की कोशिश के साथ कुछ है।
रॉल्फ

1

यह उपयोग का हो सकता है: http://www.spinellis.gr/sw/dgsh/ (निर्देशित ग्राफ शैल) "मल्टीपाइप" कमांड के लिए आसान सिंटैक्स का समर्थन करने वाले बैश रिप्लेसमेंट की तरह लगता है।


0

यहां एक त्वरित और गंदा आंशिक समाधान है, जिसमें किसी भी शेल के साथ संगत है busybox

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

  • उसी होस्ट के लिए एक और सत्र शुरू करें। इसका TTY नाम जानने के लिए, टाइप करें tty। मान लेते हैं /dev/pty/2
  • पहले सत्र में, रन the_program | tee /dev/pty/2 | grep ImportantLog:

आपको एक पूर्ण लॉग और एक फ़िल्टर किया हुआ मिलता है।

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