जब फ़ाइलनाम में रिक्त स्थान होते हैं, तो मैं कैसे उपयोग करूं?


17

मैं अन्य कार्यक्रमों में फ़ाइल नामों को पाइप करना चाहता हूं, लेकिन जब नाम में रिक्त स्थान होते हैं, तो वे सभी चोक कर देते हैं।

मान लीजिए कि मेरे पास एक फाइल है।

foo bar

मुझे findसही नाम कैसे वापस मिल सकता है ?

जाहिर है मैं चाहता हूं:

foo\ bar

या:

"foo bar"

संपादित करें : मैं नहीं जाना चाहता xargs, मैं सही ढंग से स्वरूपित स्ट्रिंग प्राप्त करना चाहता हूं findताकि मैं फ़ाइल नामों के स्ट्रिंग को सीधे दूसरे प्रोग्राम में पाइप कर सकूं।


5
आप इसे क्या कर रहे हैं? क्या आप -execझंडे के बारे में जानते हैं find? आप संभावित रूप से इस त्रुटि को कम कर सकते हैं और -execअन्य कमांडों को पाइप करने के बजाय अपनी कमांड को अधिक कुशल बना सकते हैं । बस मेरा $ .02
h3rrmiller

6
@bug: findफ़ाइल नामों को केवल ठीक स्वरूपित करता है; उन्हें प्रति पंक्ति एक नाम लिखा जाता है। (बेशक, यह अस्पष्ट है अगर एक फ़ाइल नाम में एक नया वर्ण है।) तो समस्या यह है कि रिसीविंग एंड "चोकिंग" जब इसे एक जगह मिलती है, तो इसका मतलब है कि आपको हमें यह बताना होगा कि यदि आप एक सार्थक उत्तर चाहते हैं ।
रिसी

2
जिसे आप "ठीक से स्वरूपित" कहते हैं वह वास्तव में "शेल द्वारा खपत के लिए बच गया" है। अधिकांश उपयोगिताओं जो फ़ाइल नामों का एक गुच्छा पढ़ सकती हैं, शेल-एस्कैप्ड नाम पर चोक कर देंगी, लेकिन यह वास्तव findमें शेल के लिए उपयुक्त प्रारूप में आउटपुट फ़ाइल नामों के विकल्प की पेशकश करने के लिए (कहना) के लिए समझ में आएगा । सामान्य तौर पर, हालांकि, -print0GNU findएक्सटेंशन कई अन्य परिदृश्यों (भी) के लिए ठीक काम करता है, और आपको इसे किसी भी घटना में उपयोग करना सीखना चाहिए।
ट्रिपल

2
@bug: वैसे, ls $(command...)सूची के माध्यम से फ़ीड नहीं करता है stdin। यह $(command...)सीधे कमांड लाइन में आउटपुट डालता है । उस स्थिति में, यह शेल है जो सी से पढ़ रहा है, और यह $IFSआउटपुट के शब्दों को निर्धारित करने के वर्तमान मूल्य का उपयोग करेगा । सामान्य तौर पर, आप उपयोग करना बेहतर समझते हैं xargs। आपको एक प्रदर्शन हिट की सूचना नहीं होगी।
रिची

2
find -printf '"%p"\n'प्रत्येक पाए गए नाम के आसपास दोहरे उद्धरण चिह्नों को जोड़ देगा, लेकिन फ़ाइल नाम में किसी भी दोहरे उद्धरण को ठीक से उद्धृत नहीं करेगा। यदि आपके फ़ाइल नामों में कोई एम्बेडेड दोहरे उद्धरण नहीं हैं, तो आप समस्या को अनदेखा कर सकते हैं: या पाइप के माध्यम से sed 's/"/&&/g;s/^""/"/;s/""$/"/'। यदि आपकी फ़ाइल के नाम शेल द्वारा नियंत्रित किए जा रहे हैं, तो आपको संभवतः दोहरे उद्धरणों के बजाय एकल उद्धरणों का उपयोग करना चाहिए, हालांकि (अन्यथा sweet$HOMEकुछ ऐसा ही हो जाएगा sheet/home/you)। और यह अभी भी फ़ाइल नामों के खिलाफ बहुत मजबूत नहीं है, जिसमें वे नई सुर्खियों में हैं। आप उन्हें कैसे संभालना चाहते हैं?
ट्रिपल

जवाबों:


18

POSIXLY:

find . -type f -exec sh -c '
  for f do
    : command "$f"
  done
' sh {} +

साथ findसमर्थन करता है -print0और xargsसमर्थन करता है -0:

find . -type f -print0 | xargs -0 <command>

-0 विकल्प xargs को बताता है कि फ़ाइल नाम समाप्त करने के लिए स्थान के बजाय ASCII NUL वर्ण का उपयोग करें।

उदाहरण:

find . -maxdepth 1 -type f -print0 | xargs -0 ls -l

काम नहीं करता है। जब मैं दौड़ता ls $(find . -maxdepth 1 -type f -print0 | xargs -0)हूँ तो मुझे मिलता है ls: cannot access ./foo: No such file or directory ls: cannot access bar: No such file or directory
बग

1
क्या आपने इसे उस तरह से आजमाया है जिस तरह Gnouc ने वास्तव में लिखा था? यदि आप इसे अपने तरीके से करने पर जोर देते हैं, तो $(..)दोहरे उद्धरणों में संलग्न करने का प्रयास करें"$(..)"
evilsoup

3
@bug: आपकी आज्ञा गलत है। वास्तव में मैं worte की कोशिश करो और के मैनपेज पढ़ा findऔर xargs
congonglm

मैं देखता हूं, फिर मैं एक स्वरूपित स्ट्रिंग प्राप्त करना चाहता हूं जिसे मैं सीधे पाइप कर सकता हूं।
बग

1
@bug: बस xargs -0 <your program>
cuonglm

10

उपयोग करना -print0एक विकल्प है, लेकिन सभी प्रोग्राम nullbyte- सीमांकित डेटा धाराओं का उपयोग करने का समर्थन नहीं करते हैं, इसलिए आपको कुछ चीजों के लिए विकल्प के xargsसाथ उपयोग करना होगा -0, जैसा कि Gnouc के उत्तर में उल्लेख किया गया है।

एक विकल्प का उपयोग करना होगा find की -execया -execdirविकल्प। निम्नलिखित में से पहला फाइलनाम somecommandएक बार में एक को खिलाएगा , जबकि दूसरा फाइलों की सूची में विस्तारित होगा:

find . -type f -exec somecommand '{}' \;
find . -type f -exec somecommand '{}' +

आप पा सकते हैं कि आप कई मामलों में ग्लोबिंग का उपयोग करने से बेहतर हैं। यदि आपके पास आधुनिक शेल (बैश 4+, zsh, ksh) है, तो आप globstar( **) के साथ पुनरावर्ती ग्लोबिंग प्राप्त कर सकते हैं । बैश में, आपको इसे सेट करना होगा:

shopt -s globstar
somecommand ./**/*.txt ## feeds all *.txt files to somecommand, recursively

मेरे पास shopt -s globstar extglobमेरी .bashrc में एक पंक्ति है , इसलिए यह हमेशा मेरे लिए सक्षम है (और इसलिए विस्तारित ग्लब्स हैं, जो उपयोगी भी हैं)।

यदि आप पुनरावृत्ति नहीं चाहते हैं, तो स्पष्ट रूप से ./*.txtइसके बजाय काम करने वाले निर्देशिका में प्रत्येक * .txt का उपयोग करने के लिए उपयोग करें। findकुछ बहुत ही उपयोगी बारीक-से-खोज की क्षमता है, और दसियों हज़ारों फ़ाइलों के लिए अनिवार्य है (जिस बिंदु पर आप शेल की अधिकतम संख्या में बहस करेंगे), लेकिन दिन-प्रतिदिन के उपयोग के लिए यह अक्सर अनावश्यक होता है।


अरे @evilsoup इस स्क्रिप्ट में {} क्या करता है?
आयुष्मान

3

व्यक्तिगत रूप से, मैं -execइस प्रकार की समस्या को हल करने के लिए खोज क्रिया का उपयोग करूंगा । या, यदि आवश्यक हो, xargsजो समानांतर निष्पादन की अनुमति देता है।

हालाँकि, findफ़ाइल नाम की बैश-पठनीय सूची तैयार करने का एक तरीका है । अप्रत्याशित रूप से, यह विशेष रूप से कमांड के लिए एक एक्सटेंशन का उपयोग करता है -execऔर :bashprintf

find ... -exec bash -c 'printf "%q " "$@"' printf {} ';'

हालांकि, जबकि वह सही ढंग से शेल-एस्केप किए गए शब्दों को प्रिंट करेगा, यह उसके साथ प्रयोग करने योग्य नहीं होगा $(...), क्योंकि $(...)उद्धरण या पलायन की व्याख्या नहीं करता है। ( $(...)जब तक कि शब्द बंटवारे और पथनाम विस्तार के अधीन न हो, जब तक कि उद्धरणों से घिरा न हो।) तो निम्नलिखित वह नहीं करेगा जो आप करते हैं:

ls $(find ... -exec bash -c 'printf "%q " "$@"' printf {} +)

आपको क्या करना होगा:

eval "ls $(find ... -exec bash -c 'printf "%q " "$@"' printf {} +)"

(ध्यान दें कि मैंने उपरोक्त राक्षसीता का परीक्षण करने का कोई वास्तविक प्रयास नहीं किया है।)

लेकिन तब आप भी कर सकते हैं:

find ... -exec ls {} +

मुझे नहीं लगता कि lsपरिदृश्य पर्याप्त रूप से ओपी के उपयोग के मामले को पकड़ता है, लेकिन यह केवल अटकलें हैं, क्योंकि हमें यह नहीं दिखाया गया है कि वह वास्तव में क्या हासिल करने की कोशिश कर रहा है। यह समाधान वास्तव में बहुत अच्छी तरह से काम करता है; मुझे वह आउटपुट मिलता है जिसकी मैंने (अस्पष्ट रूप से) सभी मज़ेदार फ़ाइल नामों के लिए अपेक्षा की थी, जिनमें मैंने कोशिश की थी, जिसमें शामिल हैtouch "$(tr a-z '\001-\026' <<<'the quick brown fox jumped over the lazy dogs')"
ट्रिपल जूल

@triplee: मुझे पता नहीं है कि ओपी क्या करना चाहता है। पास करने के लिए उद्धृत स्ट्रिंग के निर्माण का एकमात्र वास्तविक लाभ यह evalहै कि आपको इसे evalअभी तक पारित नहीं करना है; आप इसे एक पैरामीटर में सहेज सकते हैं और बाद में इसका उपयोग कर सकते हैं, शायद कई बार विभिन्न कमांड के साथ। हालांकि, ओपी कोई संकेत नहीं देता है कि यह उपयोग का मामला है (और यदि ऐसा था, तो फ़ाइल नाम को एक सरणी में रखना बेहतर हो सकता है, हालांकि यह बहुत मुश्किल है।)
rici

0
find ./  | grep " "

आपको फ़ाइलें और निर्देशिकाएं मिलेंगी जिनमें रिक्त स्थान होंगे

find ./ -type f  | grep " " 

आप फ़ाइलों को रिक्त स्थान होता है मिल जाएगा

find ./ -type d | grep " "

आपको मिलेगा निर्देशिका निर्देशिका में शामिल हैं


-2
    find . -type f -name \*\  | sed -e 's/ /<thisisspace>/g'

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