फ़ाइलों की सूची के रूप में 'find' का परिणाम कैसे पास करें?


11

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

mpg321 $(find /music -iname "*\.mp3")

। समस्या यह है, कुछ फ़ाइल नामों में व्हाट्सएप है, और प्रोग्राम उन नामों को छोटे भागों में तोड़ देता है और गुम फाइलों के बारे में शिकायत करता है। findउद्धरणों में परिणाम को लपेटना

mpg321 "$(find /music -iname "*\.mp3")"

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

फिर मैं यह कैसे कर सकता हूं? अगर यह मायने रखता है, तो मैं उपयोग कर रहा हूं bash, लेकिन zshजल्द ही बदल जाएगा।

जवाबों:


17

इस तरह के संयोजन में खोज -print0या -printfविकल्प का उपयोग करने का प्रयास xargsकरें:

find /music -iname "*\.mp3" -print0 | xargs -0 mpg321

यह कैसे काम करता है यह पता लगाने के मैनुअल पेज द्वारा समझाया गया है :

-print0

सच; मानक आउटपुट पर पूर्ण फ़ाइल नाम प्रिंट करें, उसके बाद एक अशक्त वर्ण (इसके बजाय न्यूलाइन वर्ण जो -प्रिंट उपयोग करता है)। यह उन फ़ाइल नामों की अनुमति देता है जिनमें नएलाइन या अन्य प्रकार के श्वेत स्थान होते हैं जिन्हें प्रोग्राम द्वारा सही तरीके से व्याख्या किया जाता है जो खोज आउटपुट को संसाधित करते हैं। यह विकल्प xargs के -0 विकल्प से मेल खाता है।


सभी संपादन के लिए क्षमा करें। मुझे लगता है कि -प्रिंट0 xarg -0 पैटर्न को अन्य प्रकार के व्हॉट्सएप पर विफल होना याद है, लेकिन मुझे एक उदाहरण नहीं मिला।
स्टीवन डी

अरे हाँ जो काम करता है! लेकिन मुझे अभी भी आश्चर्य है कि क्यों mpg321 $(find /music -iname "*\.mp3" -print0)नहीं?
फन्नेहे

1
खैर, मेरा मानना ​​है कि दो कारणों से काम नहीं करता है: (1) फ़ाइल नाम अशक्त वर्णों द्वारा अलग किए गए हैं, जो कि mpg321 बिल्कुल भी उम्मीद नहीं कर रहा है और (2) xargs अन्य व्हाट्सएप से बचने का काम कर रहा है, नहीं पाते हैं।
स्टीवन डी

2
@phunehehe, @Steven: mpg321इसका कोई लेना-देना नहीं है, यह ऐसा शेल है जो findअलग-अलग तर्कों के आउटपुट को तोड़ रहा है। और -print0 | xargs -0हर संभव फ़ाइल नाम के साथ काम करेगा।
गिल्स एसओ- बुराई को रोकना '18

8
find /music -iname "*\.mp3" -exec mpg123 {} +

जीएनयू खोजने के साथ, आप भी उपयोग कर सकते हैं -print0औरxargs -0 , लेकिन अभी तक एक और उपकरण सीखने में बहुत कम बिंदु हैं। -exec ... {} +क्योंकि लिनक्स इसे बाद में की तुलना में प्राप्त कर लिया वाक्य रचना थोड़ा उल्लेख हो जाता है -print0, लेकिन अब इसका इस्तेमाल करने के लिए नहीं कोई कारण नहीं है।

Zsh या bash 4 के साथ, यह बहुत सरल है:

mpg123 **/*.[Mm][Pp]3

केवल zsh में, आप एक (पैटर्न) केस-असंवेदनशील का हिस्सा बना सकते हैं:

mpg123 (#i)**/*.mp3

इसके लिए +1, "find -print0" एक बदसूरत हैक है।
पी-स्टेटिक

2

मुझे लगता है कि स्टीवन का समाधान सबसे अच्छा है, लेकिन एक और तरीका है xargs के -Iझंडे का उपयोग करना , जो आपको एक स्ट्रिंग निर्दिष्ट करता है जिसे तब कमांड में तर्क के साथ बदल दिया जाएगा (बजाय कमांड के अंत में तर्क को लागू करने के)। आप तर्क को उद्धृत करने के लिए इसका उपयोग कर सकते हैं:

find /music -iname "*\.mp3" | xargs -0 -Ifoo mpg321 "foo"

मुझे यह उत्तर समझ में नहीं आ रहा है ... आप -0खोज के बिना xargs के झंडे का उपयोग कर रहे हैं -print0। इसके अलावा, xargs के -Iझंडे के कई परिणाम हैं। सीधे सादे के विपरीत xargsजो एक कमांड में स्टड से सभी लाइनों को संपीड़ित करेगा, संभावित रूप से सैकड़ों या हजारों बार (प्रत्येक फ़ाइल के लिए एक बार) xargs -Iनिष्पादित करेगा mpg321जो निश्चित रूप से इरादा नहीं है। यह भी ध्यान रखें कि फू को उद्धृत करना अनावश्यक है क्योंकि xargsयह आंतरिक रूप से होता है। ध्यान दें कि यदि आप सभी फ़ाइलनामों को लाइन लाइन पर सेक करते हैं और इसे भेजते हैं xargs -I, तो वे नहीं खुलेंगे।
छह

1

यह आम तौर पर सीधे तौर पर सबसे अच्छा होता है, -exec ${tgt_process} \{\} +लेकिन अगर आपको किसी कारण से किसी फ़ाइल या स्ट्रीम में फ़ाइल नाम की विश्वसनीय रूप से सीमांकित सूची प्राप्त करने की आवश्यकता है find, तो आप ऐसा कर सकते हैं:

find -exec sh -c 'printf "///%s///\n" "$@"' -- \{\} +

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

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

लेकिन, फिर से, यह केवल आवश्यक हो तो आप सीधे नहीं कर सकता है -execआपके $tgt_processलिए जो भी कारण, के रूप में है कि अपने लक्ष्य होना चाहिए। एक बात के लिए, उपरोक्त विधि को अभी भी पार्सिंग की आवश्यकता है। उदाहरण के लिए, यदि आप प्रत्येक फ़ाइल नाम को उद्धृत करना चाहते हैं, तो आपको फ़ाइल-नाम में किसी भी हार्ड-कोट्स को सुनिश्चित करना होगा:

find ... + | sed 's|'\''|&"&"&|g;s|///|'\''|g'

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


0

ऐसा करने का एक अन्य तरीका सभी विशेष वर्णों से बचना है जो आपकी फ़ाइल नामों में आते हैं। उदाहरण के लिए:

find /music -iname "*\.mp3" | sed 's!\([] \*\$\/&[]\)!\\\1!g' | xargs mpg321

यह मूल रूप से निष्पादन के लिए xargs में ठीक से बच गए फ़ाइल नामों को पारित करेगा और कोई समस्या नहीं होगी।


1
यह अभी भी फ़ाइलनामों में नई कहानियों पर विराम लगाता है। और तुम बस के रूप में अच्छी तरह से हो सकता है sed 's|.|\\&|g'- यही POSIX वैसे भी सिफारिश करता है।
मिकसेर
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.