सशर्त पाइपलाइन


39

कहो कि मुझे निम्नलिखित पाइपलाइन मिली है:

cmd1 < input.txt |\
cmd2 |\
cmd4 |\
cmd5 |\
cmd6 |\
(...) |\
cmdN > result.txt

कुछ शर्तों के तहत मैं एक जोड़ना चाहते हैं cmd3के बीच cmd2और cmd4। क्या एक अस्थायी फ़ाइल में cmd2 के परिणाम को सहेजे बिना एक तरह की सशर्त पाइपलाइन बनाने का एक तरीका है? मैं कुछ इस तरह सोचूंगा:

cmd1 < input.txt |\
cmd2 |\
(${DEFINED}? cmd3 : cat ) |\
cmd4 |\
cmd5 |\
cmd6 |\
(...) |\
cmdN > result.txt

जवाबों:


36

बस सामान्य &&और ||ऑपरेटरों:

cmd1 < input.txt |
cmd2 |
( [[ "${DEFINED}" ]] && cmd3 || cat ) |
cmd4 |
cmd5 |
cmd6 |
(...) |
cmdN > result.txt

(ध्यान दें कि जब पाइप के साथ लाइन समाप्त होती है तो किसी भी पीछे की ओर पीछे जाने की आवश्यकता नहीं होती है।)

जोनास अवलोकन के अनुसार अद्यतन करें
यदि cmd3 गैर-शून्य निकास कोड के साथ समाप्त हो सकता है और आप catशेष इनपुट को संसाधित नहीं करना चाहते हैं , तो तर्क को उल्टा करें:

cmd1 < input.txt |
cmd2 |
( [[ ! "${DEFINED}" ]] && cat || cmd3 ) |
cmd4 |
cmd5 |
cmd6 |
(...) |
cmdN > result.txt

आसान टिप नोट!
पलटें


2
तर्क को उलटने से मदद नहीं मिलती। यदि catएक गैर-शून्य निकास स्थिति (एसआईजीपीआईपीई प्राप्त करने के दौरान आम) के साथ रिटर्न मिलता है, तो cmd3चलाया जाएगा। थोर के उत्तर या अन्य समाधानों के रूप में / या फिर / यदि चलने से बचने के लिए बेहतर उपयोग करें cat
स्टीफन चेजेलस

इसलिए बिल्ली का इस्तेमाल चीजों को जोड़ने के लिए किया जा सकता है, जैसे "स्ट्रीम" के माध्यम से
सिकंदर मिल्स

19

if/ else/ fiकार्य करता है। किसी बॉर्न की तरह खोल को मानते हुए:

cmd1 < input.txt |
cmd2 |
if [ -n "$DEFINED" ]; then cmd3; else cat; fi |
cmd4 |
cmd5 |
cmd6 |
(...) |
cmdN > result.txt

10

अब तक दिए गए सभी उत्तरों के cmd3साथ बदल जाते हैं cat। आप किसी भी कमांड को चलाने से भी बच सकते हैं:

if [ -n "$DEFINE" ]; then
  alias maybe_cmd3='cmd3 |'
else
  alias maybe_cmd3=''
fi
cmd1 |
cmd2 |
maybe_cmd3
cmd4 |
... |
cmdN > result.txt

यही कारण है कि POSIX है, लेकिन ध्यान दें कि अगर एक में bashस्क्रिप्ट जहां bashमें नहीं है shमोड (एक स्क्रिप्ट के साथ शुरू के साथ की तरह #! /path/to/bash), आप के साथ उर्फ विस्तार को सक्षम करना होगा shopt -s expand_aliases(या set -o posix)।

एक और दृष्टिकोण जो अभी भी किसी भी अनावश्यक कमांड को नहीं चलाता है वह है eval का उपयोग करना:

if [ -n "$DEFINE" ]; then
  maybe_cmd3='cmd3 |'
else
  maybe_cmd3=''
fi
eval "
  cmd1 |
  cmd2 |
  $maybe_cmd3
  cmd4 |
  ... |
  cmdN > result.txt"

या:

eval "
  cmd1 |
  cmd2 |
  ${DEFINE:+cmd3 |}
  cmd4 |
  ... |
  cmdN > result.txt"

लिनक्स पर (कम से कम), के बजाय cat, आप उन दो पाइपों के बीच डेटा को पास करने के लिए + के बजाय का उपयोग कर सकते हैं pv -qजो कर्नेल और उपयोगकर्ता स्थान के बीच दो बार स्थानांतरित किए गए डेटा से बचते हैं।splice()read()write()


9

मैनटवर्क के स्वीकृत उत्तर के परिशिष्ट के रूप में : असत्य-या- गच्छ और धाराओं के साथ इसके अंतःक्रिया से अवगत होना। उदाहरण के लिए,

true && false || echo foo

आउटपुट foo। आश्चर्य की बात नहीं है,

true && (echo foo | grep bar) || echo baz

तथा

echo foo | (true && grep bar || echo baz)

दोनों आउटपुट baz। (ध्यान दें कि echo foo | grep barगलत है और इसका कोई आउटपुट नहीं है)। तथापि,

echo foo | (true && grep bar || sed -e abaz)

आउटपुट कुछ नहीं। यह वही हो सकता है या नहीं हो सकता है जो आप चाहते हैं।


मैं नहीं देख सकता कि यह यहाँ कैसे प्रासंगिक है। else(या ||) एक अशक्त आपरेशन इनपुट अपरिवर्तित रखने के रूप में कार्य करना चाहिए। इसलिए अपने कोड को अप्रासंगिक बनाने वाले परिवर्तनों के catसाथ प्रतिस्थापित echoकरें। "और गलत-झूठ या गच्चा" के बारे में, मुझे पाइपलाइन के साथ कोई हस्तक्षेप नहीं दिखता है: pastebin.com/u6Jq0bZe
manatwork

5
@manatwork: एक बात जोनास इशारा कर रहे हैं कि, में [[ "${DEFINED}" ]] && cmd3 || cat, cmd3और समान catरूप से अनन्य thenऔर elseशाखाएं नहीं हैं if, लेकिन अगर वह cmd3विफल रहता है, तो catभी निष्पादित किया जाएगा। (बेशक, अगर cmd3हमेशा सफल होता है, या अगर यह सभी इनपुट का उपभोग करता है, तो प्रक्रिया के stdinलिए कुछ भी नहीं बचा है cat, तो यह कोई फर्क नहीं पड़ सकता है।) यदि आपको दोनों thenऔर elseशाखाओं की आवश्यकता है , तो एक स्पष्ट ifआदेश का उपयोग करना बेहतर है , न कि &&और ||
मुसीफिल

1
स्पष्टीकरण के लिए धन्यवाद, @musiphil। अब मुझे जोनास का तर्क समझ में आया।
मैनटवर्क

4

मेरे पास एक ऐसी स्थिति थी जिसे मैंने बैश कार्यों के साथ हल किया था :

if ...; then
  my_cmd3() { cmd3; }
else
  my_cmd3() { cat; }
if

cmd1 < input.txt |
cmd2 |
my_cmd3 |
cmd4 |
cmd5 |
cmd6 |
(...) |
cmdN > result.txt

3

यहां एक वैकल्पिक संभव समाधान है:
छद्म पाइपलाइन बनाने के लिए नामित पाइप को समतल करना:

dir="$(mktemp -d)"
fifo_n='0'
function addfifo {
 stdin="$dir/$fifo_n"
((fifo_n++))
[ "$1" ] || mkfifo "$dir/$fifo_n"
stdout="$dir/$fifo_n"; }

addfifo; echo "The slow pink fox crawl under the brilliant dog" >"$stdout" &

# Restoring the famous line: "The quick brown fox jumps over the lazy dog"
# just replace 'true' with 'false' in any of the 5 following lines and the pseudo-pipeline will still work
true && { addfifo; sed 's/brilliant/lazy/' <"$stdin" >"$stdout" & }
true && { addfifo; sed 's/under/over/'     <"$stdin" >"$stdout" & }
true && { addfifo; sed 's/crawl/jumps/'    <"$stdin" >"$stdout" & }
true && { addfifo; sed 's/pink/brown/'     <"$stdin" >"$stdout" & }
true && { addfifo; sed 's/slow/quick/'     <"$stdin" >"$stdout" & }

addfifo -last; cat <"$stdin"

wait; rm -r "$dir"; exit 0

2

भविष्य के संदर्भ के लिए, यदि आप मछली में सशर्त पाइप की तलाश में यहां आ रहे हैं, तो यह है कि आप इसे कैसे करते हैं:

set -l flags "yes"
# ... 
echo "conditionalpipeline" | \
  if contains -- "yes" $flags 
    sed "s/lp/l p/"
  else
    cat
  end | tr '[:lower:]' '[:upper:]'
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.