बाश के "मैपफाइल" में पाइप नहीं कर सकते ... लेकिन क्यों?


13

मैं बस एक निश्चित निर्देशिका में सभी फाइलों को बैश सरणी में लाना चाहता हूं (यह मानते हुए कि फाइलों में से कोई भी नाम में एक नई पंक्ति नहीं है):

इसलिए:

myarr=()
find . -maxdepth 1  -name "mysqldump*" | mapfile -t myarr; echo "${myarr[@]}"

खाली परिणाम!

यदि मैं किसी फ़ाइल का उपयोग करने का राउंडअबाउट तरीका अस्थायी या अन्यथा करता हूँ:

myarr=()
find . -maxdepth 1  -name "mysqldump*" > X
mapfile -t myarray < X
echo "${myarray[@]}"

परिणाम!

लेकिन mapfileएक पाइप से ठीक से क्यों नहीं पढ़ा जाता है?



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

2
यदि आप शेलचेक को कोड देते हैं , तो आपको चेतावनियाँ मिलती हैं: SC2030 : "var का संशोधन स्थानीय है (पाइपलाइन से होने वाली सबस्क्रिप्शन के लिए )" और SC2031 : "var को एक सबशेल में संशोधित किया गया था। यह परिवर्तन खो सकता है।" । अति उत्कृष्ट।
डेविड टोनहोफर

क्यों findऔर mapfileयहाँ का उपयोग कर रहे हैं और बस नहीं myarr=(mysqldump*)? यह भी रिक्त स्थान और newlines के साथ फ़ाइल नाम के साथ काम करेंगे।
ब्लैकजैक

1
केवल इस बात पर ध्यान दिया जाता है कि किसी फाइल के मिलान के मामले में सरणी के साथ समाप्त न होने के लिए nullglob( shopt -s nullglob) को चालू करना है । myarr=(mysqldump*)('mysqldump*')
डेविड टोनहोफर

जवाबों:


25

से man 1 bash:

एक पाइप लाइन में प्रत्येक कमांड को एक अलग प्रक्रिया के रूप में निष्पादित किया जाता है (यानी, एक सबशेल में)।

इस तरह की उपधाराएं मुख्य शेल से चर प्राप्त करती हैं लेकिन वे स्वतंत्र हैं। इसका मतलब है mapfileकि आपकी मूल कमान अपने आप संचालित होती है myarr। तब echo(पाइप के बाहर होना) खाली प्रिंट करता है myarr(जो मुख्य शेल है myarr)।

यह कमांड अलग तरीके से काम करती है:

find . -maxdepth 1 -name "mysqldump*" | { mapfile -t myarr; echo "${myarr[@]}"; }

इस मामले में mapfileऔर echoउसी पर काम करें myarr(जो मुख्य शेल नहीं है myarr)।

मुख्य शेल को बदलने के लिए आपको मुख्य शेल में myarrभागना होगा mapfile। उदाहरण:

myarr=()
mapfile -t myarr < <(find . -maxdepth 1 -name "mysqldump*")
echo "${myarr[@]}"

अटारी की प्रतिक्रिया में दिए गए लिंक को "प्रॉसेस सब्स्टीट्यूशन" से जोड़ा गया है, यदि किसी आगंतुक के पास टीएल; डीआर पल है।
डेविड टोनहोफर

11

बैश एक उप-वातावरण में एक पाइप लाइन की कमांड चलाता है, इसलिए इसके भीतर होने वाले किसी भी चर असाइनमेंट आदि को शेल के बाकी हिस्सों में दिखाई नहीं देता है।

डैश (डेबियन /bin/sh) के साथ-साथ बिजीबॉक्स shभी समान हैं, जबकि zsh और ksh मुख्य शेल में अंतिम भाग चलाते हैं। बैश में, आप ऐसा करने के shopt -s lastpipeलिए उपयोग कर सकते हैं , लेकिन यह केवल तभी काम करता है जब नौकरी नियंत्रण अक्षम हो, इसलिए डिफ़ॉल्ट रूप से इंटरैक्टिव गोले में नहीं।

इसलिए:

$ bash -c 'x=a; echo b | read x; echo $x'
a
$ bash -c 'shopt -s lastpipe; x=a; echo b | read x; echo $x'
b

( readऔर mapfileएक ही मुद्दा है।)

वैकल्पिक रूप से (और जैसा कि अटेई ने उल्लेख किया है), प्रक्रिया प्रतिस्थापन का उपयोग करें , जो एक सामान्यीकृत पाइप की तरह काम करता है, और बैश, ksh और zsh में समर्थित है।

$ bash -c 'x=a; read x < <(echo b); echo $x'
b

POSIX इसे अनिर्दिष्ट छोड़ देता है यदि किसी पाइपलाइन के भाग उप-भागों में चलते हैं या नहीं, तो यह वास्तव में नहीं कहा जा सकता है कि इसमें से कोई भी शेल "गलत" होगा।


2
यदि आप बैश के जॉब कंट्रोल को निष्क्रिय कर देते हैं, तो आप इंटरएक्टिव शेल में लास्टपाइप का उपयोग कर सकते हैं:set +m; shopt -s lastpipe; x=a; echo b | read x; echo $x; set -m
साइरस

@ साइरस, आह ठीक है, मैं विवरण भूल गया, धन्यवाद
ilkachachu

9

जैसा कि कामिल ने बताया है, पाइपलाइन में प्रत्येक तत्व एक अलग प्रक्रिया है।

आप एक अलग प्रक्रिया में चलने के लिए निम्नलिखित प्रक्रिया के प्रतिस्थापन का उपयोग कर सकते हैं find, mapfileअपने वर्तमान दुभाषिया में बचे हुए आह्वान के साथ , myarrबाद में पहुंच की अनुमति देते हैं :

myarr=()
mapfile -t myarr < <( find . -maxdepth 1  -name "mysqldump*" )
echo "${myarr[@]}"

b < <( a )इसी तरह से कार्य करेगा a | bकि कैसे पाइपलाइन को तार दिया जाता है - अंतर यह है कि b" यहां " निष्पादित किया जाता है ।

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