आज्ञा क्यों नहीं है "ls | फ़ाइल ”काम?


32

मैं कमांड लाइन के बारे में अध्ययन कर रहा हूं और सीखा है कि |(पाइपलाइन) एक कमांड से आउटपुट को दूसरे के इनपुट पर रीडायरेक्ट करने के लिए है। तो कमांड क्यों ls | fileकाम नहीं करता है?

file इनपुट अधिक फ़ाइल नाम में से एक है, जैसे file filename1 filename2

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

जब मैं इसका उपयोग करता हूं, तो आउटपुट होता है:

    Usage: file [-bcEhikLlNnprsvz0] [--apple] [--mime-encoding] [--mime-type]
        [-e testname] [-F separator] [-f namefile] [-m magicfiles] file ...
    file -C [-m magicfiles]
    file [--help]

चूंकि fileकमांड के उपयोग में कुछ त्रुटि थी


2
यदि आप सादे का उपयोग कर रहे हैं ls, तो यह इंगित करता है कि आप मौजूदा निर्देशिका में सभी फाइलें fileकमांड के साथ संभालना चाहते हैं । ... तो बस क्यों न करें:, file *जो हर फ़ाइल, फ़ोल्डर के लिए एक पंक्ति के साथ उत्तर देगा।
नुड लार्सन

file *सबसे अच्छा तरीका है, मैं बस सोच रहा था कि lsआउटपुट का उपयोग करना काम क्यों नहीं कर रहा था। संदेह साफ हो गया :)
IanC

6
आधार त्रुटिपूर्ण है: "फ़ाइल इनपुट अधिक फ़ाइलनामों में से एक है, जैसे फ़ाइल फ़ाइलनाम 1 फ़ाइलनाम 2" यह इनपुट नहीं है। वे कमांड लाइन तर्क हैं, जैसा कि @ जॉन कुगेलमैन नीचे बताते हैं।
मोंटी हार्डर

3
आमतौर पर , पार्सिंगls आमतौर पर एक बुरा विचार है।
कोजीरो '

जवाबों:


71

मूल मुद्दा यह है कि file फ़ाइल नामों को कमांड-लाइन तर्कों के रूप में देखा जाता है, न कि स्टडिन पर। जब आप लिखते हैं ls | fileके आउटपुट lsको इनपुट के रूप में पास किया जा रहा है file। तर्कों के रूप में नहीं, इनपुट के रूप में।

क्या फर्क पड़ता है?

  • कमांड-लाइन तर्क तब होते हैं जब आप एक कमांड के बाद झंडे और फ़ाइल नाम लिखते हैं, जैसे कि cmd arg1 arg2 arg3। शेल स्क्रिप्ट में इन तर्कों चर के रूप में उपलब्ध हैं $1, $2, $3, आदि में सी आप उन्हें के माध्यम से पहुंच चाहते हैं char **argvऔर int argcतर्कों कोmain()

  • मानक इनपुट, स्टडिन, डेटा की एक धारा है। जब वे कोई कमांड-लाइन तर्क नहीं देते हैं, तो कुछ प्रोग्राम स्टड से पढ़ते हैं catया wcपढ़ते हैं। एक शेल स्क्रिप्ट में आप readइनपुट की एक लाइन प्राप्त करने के लिए उपयोग कर सकते हैं । C में आप उपयोग कर सकते हैं scanf()याgetchar() विभिन्न विकल्पों के बीच , का ।

fileआम तौर पर स्टड से नहीं पढ़ता है। यह कम से कम एक फ़ाइल नाम को एक तर्क के रूप में पारित करने की अपेक्षा करता है। इसीलिए जब आप लिखते हैं तो यह उपयोग को प्रिंट करता हैls | file , क्योंकि आपने एक तर्क पारित नहीं किया था।

आप xargsस्टड को तर्कों में बदलने के लिए उपयोग कर सकते हैं , जैसे कि ls | xargs file। फिर भी, टेर्डन के उल्लेख के अनुसार , पार्सिंग lsएक बुरा विचार है। ऐसा करने का सबसे सीधा तरीका है:

file *

2
या fileइसके प्रयोग से फ़ाइल नाम प्राप्त करने के लिए मजबूर करें ls | file -f -। फिर भी toc का एक बुरा विचार।
स्पेक्टर्स

2
@Braiam> यह बात है। और उस पाइप lsका आउटपुट fileस्टडिन में है। कोशिश करके देखो।
स्पेक्टर्स

4
@Braiam> वास्तव में यह बेकार और खतरनाक है। लेकिन यह काम करता है और यह बेहतर है कि बेहतर विकल्पों की तुलना करें यदि ओपी पुनर्निर्देशन का उपयोग करना सीख रहा है। पूर्णता के लिए मैं यह भी उल्लेख कर सकता हूं file $(ls), जो काम भी करता है, फिर भी दूसरे तरीके से।
स्पेक्टर्स

2
मुझे लगता है कि सभी उत्तरों को पढ़ने के बाद मेरे पास इस मुद्दे की एक बड़ी तस्वीर है, हालांकि मुझे लगता है कि मुझे यह सब समझने के लिए आगे पढ़ने की आवश्यकता होगी। सबसे पहले, जाहिरा तौर पर पाइपिंग और पुनर्निर्देशन का उपयोग आउटपुट को तर्कों के रूप में नहीं करता है , लेकिन एसटीडीआईएन के रूप में । जिसे मुझे अभी भी बेहतर समझने के लिए आगे पढ़ना है, लेकिन सतही खोज के तर्क देने से ऐसा लगता है जैसे पाठ किसी सरणी में प्रोग्राम को पार्स किया जा रहा है, और एसटीडीआईएन एक फ़ाइल या आउटपुट के लिए जानकारी पूल करने के तरीके की तरह है (सभी प्रोग्राम डिज़ाइन नहीं किए जा रहे हैं इस "पूलिंग" के साथ काम करें)
IanC

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

18

क्योंकि, जैसा कि आप कहते हैं, फ़ाइल नाम का इनपुट fileहोना चाहिए । का उत्पादनlsहालाँकि, का सिर्फ पाठ है। ऐसा होता है कि फ़ाइल नामों की एक सूची होती है यह इस तथ्य को नहीं बदलता है कि यह केवल पाठ है और हार्ड ड्राइव पर फ़ाइलों का स्थान नहीं है।

जब आप स्क्रीन पर मुद्रित आउटपुट देखते हैं, तो आप जो देखते हैं वह टेक्स्ट है। चाहे वह पाठ एक कविता हो या फ़ाइलनाम की सूची से कंप्यूटर पर कोई फर्क नहीं पड़ता। यह सब पता है कि यह पाठ है। यही कारण है कि आप उन lsकार्यक्रमों के आउटपुट को पास कर सकते हैं जो पाठ को इनपुट के रूप में लेते हैं (हालांकि आप वास्तव में, वास्तव में नहीं होना चाहिए ):

$ ls / | grep etc
etc

इसलिए, कमांड के आउटपुट का उपयोग करने के लिए जो फ़ाइल नामों को सूचीबद्ध करता है जैसे टेक्स्ट (जैसे lsया find) कमांड के लिए इनपुट के रूप में जो फ़ाइल नाम लेता है, आपको कुछ ट्रिक्स का उपयोग करने की आवश्यकता है। इसके लिए विशिष्ट उपकरण है xargs:

$ ls
file1 file2

$ ls | xargs wc
 9  9 38 file1
 5  5 20 file2
14 14 58 total

जैसा कि मैंने पहले कहा था, हालांकि, आप वास्तव में के उत्पादन को पार्स नहीं करना चाहते हैं ls। की तरह कुछ findबेहतर है ( print0प्रिंट एक \0प्रत्येक फ़ाइल नाम के बाद एक newilne के बजाय और -0की xargsयह इस तरह इनपुट से निपटने की सुविधा देता है, यह फ़ाइल नाम नई-पंक्तियों से युक्त के साथ अपने आदेशों काम करने के लिए एक चाल है):

$ find . -type f -print0 | xargs -0 wc
 9  9 38 ./file1
 5  5 20 ./file2
14 14 58 total

जिसके पास ऐसा करने का अपना तरीका भी है, बिना आवश्यकता के xargs:

$ find . -type f -exec wc {} +
 9  9 38 ./file1
 5  5 20 ./file2
14 14 58 total

अंत में, आप शेल लूप का भी उपयोग कर सकते हैं। हालांकि, ध्यान दें कि ज्यादातर मामलों में, xargsबहुत तेज और अधिक कुशल होगा। उदाहरण के लिए:

$ for file in *; do wc "$file"; done
 9  9 38 file1
 5  5 20 file2

एक पक्ष मुद्दा यह है कि है fileवास्तव में stdin पढ़ने के लिए प्रकट नहीं होता है जब तक कि एक स्पष्ट दिया -प्लेसहोल्डर: तुलना file foo, echo foo | fileऔर echo foo | file -; वास्तव में यह शायद ओपीएस मामले में उपयोग संदेश का कारण है (यानी यह वास्तव में इसलिए नहीं है क्योंकि इसका उत्पादन ls"बस पाठ" है, बल्कि इसलिए कि तर्क सूची fileखाली है)
इस्पात ज्वर

@steeldriver हाँ। AFAIK उन सभी कार्यक्रमों के लिए मामला है जो फ़ाइलों की अपेक्षा करते हैं और इनपुट के रूप में पाठ नहीं। वे केवल डिफ़ॉल्ट रूप से स्टड को अनदेखा करते हैं। ध्यान दें कि echo foo | file -वास्तव fileमें फ़ाइल पर नहीं fooबल्कि स्टडिन स्ट्रीम पर चलता है।
terdon

अच्छी तरह से वहाँ अजीब बतख (?) की तरह है catकि बिना स्टडिन को -छोड़कर जब दिए गए फ़ाइल तर्क के रूप में अच्छी तरह से मुझे लगता है?
स्टीलड्राइवर

3
यह उत्तर स्टडिन और कमांड लाइन के तर्कों के बीच के अंतर को समझाने में विफल रहता है, और इसलिए, स्वीकृत उत्तर की तुलना में बिंदु पर अधिक होने के बावजूद, अभी भी उसी कारण से गहरा भ्रामक है।
५२ पर ज्वॉल

5
@terdon मुझे लगता है कि इस मामले में एक गंभीर त्रुटि है। "फ़ाइल (1) कमांड लाइन के तर्कों के रूप में संचालित करने के लिए फ़ाइलों की सूची लेता है, न कि मानक इनपुट के रूप में" यह समझने के लिए मौलिक है कि ओपी की कमांड क्यों काम नहीं करती है, और भेद सामान्य रूप से शेल स्क्रिप्टिंग के लिए मौलिक है; आप उन पर भरोसा करके उन्हें कोई एहसान नहीं कर रहे हैं।
५० पर जूल

6

सीखा कि '|' (पाइपलाइन) एक कमांड से आउटपुट को दूसरे के इनपुट पर पुनर्निर्देशित करने के लिए है।

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

आप क्या कर सकते हैं फ़ाइल नाम से फ़ाइल के --files-fromविकल्प के साथ फ़ाइल पढ़ सकते हैं यदि आपके पास एक फ़ाइल है जो उन सभी फ़ाइलों को सूचीबद्ध करती है जिन्हें आप परीक्षण करना चाहते हैं, अन्यथा केवल तर्क के रूप में आपकी फ़ाइलों के लिए पथ पास करें।


6

स्वीकृत उत्तर बताता है कि पाइप कमांड सीधे काम क्यों नहीं करता है, और file *कमांड के साथ , यह एक सरल, सीधा समाधान प्रदान करता है।

मैं एक और विकल्प सुझाना चाहता हूं जो कुछ समय में काम आ सकता है। ट्रिक backtick (`)कैरेक्टर का इस्तेमाल कर रही है । बैकटिक को यहाँ पर विस्तार से समझाया गया है । संक्षेप में, यह backticks में संलग्न कमांड के आउटपुट को लेता है और इसे शेष कमांड में स्ट्रिंग के रूप में प्रतिस्थापित करता है।

इसलिए, कमांड find `ls`का आउटपुट लेगा ls, और कमांड के तर्क के रूप में इसे findबदलेगा। यह स्वीकृत समाधान की तुलना में अधिक लंबा और अधिक जटिल है, लेकिन इस तरह के वेरिएंट अन्य स्थितियों में सहायक हो सकते हैं।


मैं लिनक्स पर कमांड लाइन का उपयोग करने के बारे में एक पुस्तक पढ़ रहा हूं (संदेह मुझे इसके साथ प्रयोग करने से आया था), और संयोग से मैंने सिर्फ "कमांड प्रतिस्थापन" के बारे में पढ़ा। आप बाश में एक कमांड के आउटपुट का विस्तार करने के लिए $ (कमांड) या command(मेरे फोन पर बैकस्लैश कोड नहीं पा सकते हैं ) का उपयोग कर सकते हैं और इसे अन्य कमांड के पैरामीटर के रूप में उपयोग कर सकते हैं। वास्तव में उपयोगी है, भले ही इस मामले में इसका उपयोग ( ls के साथ ) अभी भी कुछ मुद्दों पर परिणाम होगा क्योंकि कुछ फ़ाइलनामों पर विशेष वर्ण।
आईएएनसी

@ आईएनसी दुर्भाग्यवश, अधिकांश किताबें और ट्यूटोरियल वहाँ के बारे में बताते हैं कि कचरा, बुरी प्रथाओं से वंचित है, पदावनत वाक्यविन्यास, सूक्ष्म कीड़े; (एकमात्र) भरोसेमंद संदर्भों के बारे में बताते हैं कि बैश डेवलपर्स हैं, अर्थात् , मैनुअल और #bash आईआरसी चैनल फ़्रीनोड पर (चैनल विषय में जुड़े संसाधनों की भी जांच करें)।
इगनिस

1
कमांड प्रतिस्थापन का उपयोग करना कई बार वास्तव में सहायक हो सकता है, लेकिन इस संदर्भ में यह बहुत विकृत है - विशेष रूप से एलएस के साथ।
जो

यह भी संबंधित: unix.stackexchange.com/a/5782/107266
मैथ

5

lsएक पाइप के माध्यम से आउटपुट 0x0a के साथ डेटा का एक ठोस ब्लॉक है जो प्रत्येक पंक्ति को अलग करता है - यानी एक लाइनफ़ीड चरित्र - और fileइसे एक पैरामीटर के रूप में प्राप्त होता है, जहां यह एक समय में एक से अधिक वर्णों को काम करने की अपेक्षा करता है।

एक सामान्य नियम के रूप में, lsअन्य कमांड के लिए डेटा स्रोत उत्पन्न करने के लिए कभी भी उपयोग न करें - एक दिन यह पाइप करेगा .. rmऔर फिर आप मुसीबत में हैं!

एक लूप का उपयोग करने के लिए बेहतर है, जैसे कि for i in *; do file "$i" ; doneआप चाहते हैं कि उत्पादन का उत्पादन होगा, भविष्यवाणी। रिक्त स्थान के साथ फ़ाइल नाम के मामले में उद्धरण हैं।


8
आसान: file *;-)
Wayne_Yux

3
@IanC मैं वास्तव में पर्याप्त नहीं बता सकता कि इस बात का उत्पादन को पार्स lsएक है बहुत, बहुत बुरा विचार । न केवल इसलिए कि आप इसे कुछ हानिकारक जैसे कि rmअधिक महत्वपूर्ण रूप से पास कर सकते हैं क्योंकि यह किसी भी गैर-मानक फ़ाइल नाम पर टूट जाता है।
terdon

5
पहला पैराग्राफ कहीं न कहीं भ्रामक और सीधी बकवास के बीच है। लाइनफीड की कोई प्रासंगिकता नहीं है। दूसरा पैराग्राफ गलत कारण के लिए सही है। Ls को पार्स करना बुरा है, लेकिन इसलिए नहीं कि यह किसी तरह जादुई रूप से "पाइप" से rm हो सकता है।
जॉन कुगेलमैन

1
क्या rmमानक इनपुट से फाइलनेम लेते हैं? मुझे नहीं लगता। इसके अलावा, एक सामान्य नियम के रूप में, lsयूनिक्स की शुरुआत के बाद से यूनिक्स पाइपलाइनों के उपयोग के लिए डेटा स्रोत के प्रमुख उदाहरणों में से एक रहा है। यही कारण है कि यह एक साधारण एक-फ़ाइल नाम-प्रति-पंक्ति है जिसमें कोई विशेषता या श्रंगार नहीं है, जब यह आउटपुट पाइप होता है, तो इसके सामान्य डिफ़ॉल्ट स्वरूपण के विपरीत जब आउटपुट टर्मिनल होता है।
दाविदबक

2
@DewiMorgan यह वेबसाइट मुख्य रूप से एक गैर-तकनीकी दर्शकों पर लक्षित है, इसलिए यहां बुरी आदतों को फैलाना / प्रोत्साहित करना नुकसान करता है और कुछ भी अच्छा नहीं करता है। Unix.SE या अन्य तकनीकी समुदाय पर, जिनके उपयोगकर्ताओं को बिना पैरों की शूटिंग के अपने पैरों के बहुत करीब से लक्ष्य करने का ज्ञान / साधन है, आपकी बात (अन्य प्रथाओं के बारे में) पकड़ सकती है, लेकिन यहां यह आपकी टिप्पणी को स्मार्ट नहीं बनाती है।
इग्निस

4

यदि आप एक fileविकल्प का उपयोग करने के लिए एक पाइप का उपयोग करना चाहते हैं, -fजो सामान्य रूप से एक फ़ाइल नाम के बाद है, लेकिन आप स्टड -से पढ़ने के लिए एक एकल हाइफ़न का भी उपयोग कर सकते हैं , इसलिए

$ ls
cow.pdf  some.txt
$ ls | file -f -
cow.pdf:       PDF document, version 1.4
some.txt:        ASCII text

हाइफ़न के साथ चाल -कई मानक कमांड-लाइन बर्तनों के साथ काम करती है (हालांकि यह --कभी-कभी होता है), इसलिए यह हमेशा एक कोशिश के लायक है।

टूल xargबहुत अधिक शक्तिशाली है और ज्यादातर मामलों में केवल तभी आवश्यक है जब तर्क-सूची बहुत लंबी हो ( विवरण के लिए इस पोस्ट को देखें)।


कब है --? मैंने ऐसा कभी नहीं देखा। --आम तौर पर "झंडे का अंत" सूचक होता है।
जॉन कुगेलमैन मोनिका जूल

हां, लेकिन मैंने इसे प्रोग्रामर द्वारा उस तरह से इस्तेमाल किए गए कुछ उदाहरणों (एब) में पाया। मुझे याद नहीं है कि वास्तव में मैं क्या करूँगा (अगर मैं करूँगा तो एक टिप्पणी जोड़ दूंगा) लेकिन मुझे याद है कि मैंने जो शाप दिया था जब मुझे पता चला था और ये शाप निश्चित रूप से NSFW ;-)
deamentiaemundi

2

यह नीचे की तरह कमांड का उपयोग करता है

ls | xargs file

यह मेरे लिए बेहतर काम करेगा


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