खोजने के साथ एक निश्चित उपनिर्देशिका को छोड़कर सभी फ़ाइलों को हटा दें


11

मैं aसबफ़ोल्डर में सभी फ़ाइलों को छोड़कर, फ़ोल्डर में थोड़ी देर में एक्सेस नहीं की गई सभी फ़ाइलों को पुन: हटाना चाहता हूं b

find a \( -name b -prune \) -o -type f -delete

हालाँकि, मुझे एक त्रुटि संदेश मिला:

खोजें: -Dlete क्रिया स्वचालित रूप से -depth को चालू कर देती है, लेकिन -depth प्रभावी होने पर कुछ भी नहीं करता है। यदि आप किसी भी तरह से ले जाना चाहते हैं, तो बस स्पष्ट रूप से -depth विकल्प का उपयोग करें।

जोड़ना -depthकारणों में सभी फाइलों bको शामिल किए जाने, जो चाहिए नहीं होता है।

किसी को भी यह काम करने का एक सुरक्षित तरीका पता है?


@ माइकलकॉर्जलिंग: मैंने एक्ग्लोब पर एक नज़र डाली थी, लेकिन आप सब कुछ aछोड़कर कैसे शामिल करते हैं a/b?
forthrin

cd a && ls -d !(b/*)काम नहीं करेगा ? (ऐसा करने के लिए, rm -rबल्कि इसके बजाय ls -d।)
एक CVn

आपका सुझाव सबफ़ोल्डर्स को हटा देता है। मैं फ़ोल्डरों को बरकरार रखना चाहता हूं। मैं पेड़ के नीचे की सभी फाइलों को ढूंढना और हटाना चाहता हूं a(फाइलों के अलावा a/b)।
आगेिन

तो बस -rrm को स्किप करें । ऐसा लगता है कि आप जिस चीज के बारे में पूछ रहे हैं वह बैश के विस्तारित ग्लोबिंग का उपयोग करके आसानी से उत्तर दिया गया है, और फिर ग्लोबिंग के परिणाम के साथ आप क्या करते हैं यह आपके ऊपर है।
बजे एक CVn

@ MichaelKjörling सिर्फ इसलिए कि दो समस्याओं में अस्पष्ट-सा समाधान है, सवालों को दोहरा नहीं बनाता है। दो समस्याओं में से प्रत्येक के लिए अधिकांश समाधान अन्य समस्या का समाधान नहीं करते हैं।
गिल्स एसओ- बुराई को रोकना '

जवाबों:


13

टीएल; डीआर: सबसे अच्छा तरीका है -exec rmइसके बजाय उपयोग करना है -delete

find a \( -name b -prune \) -o -type f -exec rm {} +

स्पष्टीकरण:

क्यों मिल रहा है शिकायत है जब आप इस्तेमाल करने की कोशिश -deleteके साथ -prune?

संक्षिप्त उत्तर: क्योंकि -deleteतात्पर्य है -depthऔर अप्रभावी -depthबनाता है -prune

इससे पहले कि हम लंबे उत्तर पर आएं, पहले और साथ में पाए जाने वाले व्यवहार को देखें -depth:

$ find foo/
foo/
foo/f1
foo/bar
foo/bar/b2
foo/bar/b1
foo/f2

एकल निर्देशिका में आदेश के बारे में कोई गारंटी नहीं है। लेकिन इस बात की गारंटी है कि किसी निर्देशिका को उसकी सामग्री से पहले संसाधित किया जाता है। नोट foo/किसी भी पहले foo/*और foo/barकिसी भी पहले foo/bar/*

इससे उलटा हो सकता है -depth

$ find foo/ -depth
foo/f2
foo/bar/b2
foo/bar/b1
foo/bar
foo/f1
foo/

ध्यान दें कि अब सभी foo/*पहले दिखाई देते हैं foo/। उसी के साथ foo/bar

दीर्घ उत्तर:

  • -pruneएक निर्देशिका में उतरने से रोकता है। दूसरे शब्दों -pruneमें निर्देशिका की सामग्री को छोड़ देता है। आपके मामले -name b -pruneमें नाम के साथ किसी भी निर्देशिका में उतरने से रोकता है b
  • -depthनिर्देशिका से पहले ही किसी निर्देशिका की सामग्री को संसाधित करने के लिए खोज करता है। इसका मतलब यह है कि जब तक निर्देशिका की प्रविष्टि की प्रक्रिया शुरू नहीं हो जाती, तब तक bइसकी सामग्री पहले ही संसाधित हो चुकी होती है। इस प्रकार प्रभाव -pruneसे अप्रभावी -depthहै।
  • -deleteतात्पर्य है -depthकि यह फ़ाइलों को पहले और फिर खाली निर्देशिका को हटा सकता है। -deleteगैर-रिक्त निर्देशिका को हटाने से इंकार करना। मुझे लगता है कि -deleteगैर-खाली निर्देशिकाओं को हटाने और / या रोकने के -deleteलिए मजबूर करने के लिए एक विकल्प जोड़ना संभव होगा -depth। लेकिन वो दूसरी कहानी है।

आप जो चाहते हैं उसे प्राप्त करने का एक और तरीका है:

find a -not -path "*/b*" -type f -delete

यह याद रखना आसान हो भी सकता है और नहीं भी।

यह कमांड अभी भी डायरेक्टरी में उतरता है bऔर इसमें हर एक फाइल को केवल उन्हीं के -notलिए अस्वीकार करता है। यदि निर्देशिका bबड़ी है , तो यह एक प्रदर्शन समस्या हो सकती है।

-pathसे अलग काम करता है -name। संपूर्ण पथ के विरुद्ध मिलान -nameकरते समय केवल नाम (फ़ाइल या निर्देशिका के) -pathसे मेल खाता है। उदाहरण के लिए पथ का निरीक्षण करें /home/lesmana/foo/bar-name -barमिलान कर देंगे क्योंकि नाम है bar-path "*/foo*"मिलान होगा क्योंकि स्ट्रिंग /fooपथ में है। -pathकुछ पेचीदगियों का उपयोग करने से पहले आपको समझना चाहिए। findअधिक विवरण के लिए मैन पेज पढ़ें ।

खबरदार कि यह 100% मूर्ख नहीं है। "झूठी सकारात्मक" की संभावना है। जिस तरह से कमांड ऊपर लिखा गया है वह किसी भी फ़ाइल को छोड़ देगा जिसमें कोई भी मूल निर्देशिका है जिसका नाम b(सकारात्मक) के साथ शुरू हो रहा है । लेकिन यह किसी भी फ़ाइल को छोड़ देगा जो नाम bपेड़ में स्थिति की परवाह किए बिना (झूठी सकारात्मक) के साथ शुरू हो रहा है। इससे बेहतर अभिव्यक्ति लिखकर इसे ठीक किया जा सकता है "*/b*"। इसे पाठक के लिए एक अभ्यास के रूप में छोड़ दिया जाता है।

मुझे लगता है कि आपने उपयोग किया aऔर bप्लेसहोल्डर के रूप में और असली नाम अधिक पसंद हैं allosaurusऔर brachiosaurus। यदि आप उसकी brachiosaurusजगह रखते हैं bतो झूठी सकारात्मकता की मात्रा में भारी कमी आएगी।

कम से कम झूठी सकारात्मकता को हटाया नहीं जाएगा , इसलिए यह उतना दुखद नहीं होगा। इसके अलावा, आप पहले बिना कमांड चलाकर झूठी सकारात्मकता की जांच कर सकते हैं -delete(लेकिन निहित को याद रखना -depth) और आउटपुट की जांच करना।

find a -not -path "*/b*" -type f -depth

-not -pathबस बात थी! एक उदार व्याख्या के लिए धन्यवाद!
इरिना

1
क्यों -not -pathकाम -pruneनहीं करता है पर कुछ विस्तार सहायक होगा। -not -pathसह-अस्तित्व क्यों हो सकता है -depth?
फहीम मीठा

3

rmइसके बजाय बस का उपयोग करें -delete:

find a -name b -prune -o -type f -exec rm -f {} +

1
तुम क्यों rmकाम करता है और deleteनहीं पर विस्तृत कर सकते हैं ?
फहीम मीठा

1
ओह, मुझे शायद लगता है क्योंकि "-टेली ने गैर-खाली निर्देशिकाओं को हटाने से इनकार कर दिया है।" इसलिए गैर-रिक्त निर्देशिका को हटाने से इंकार कर दें। लेकिन rmउस समस्या नहीं है। लेकिन, चाहे, विस्तार एक अच्छी बात होगी।
फहीम मीठा

@FaheemMitha, उस का जवाब सवाल में है। -deleteतात्पर्य -depth, जो स्पष्ट रूप से साथ काम नहीं कर सकता -prune-pathकाम करता है, लेकिन findनिर्देशिकाओं में उतरने से नहीं रोकता है जिसे इसे तलाशने की आवश्यकता नहीं है।
स्टीफन चेज़लस

0

उपरोक्त उत्तर और स्पष्टीकरण बहुत मददगार थे।

मैं "-exec rm {} +" या "-not -path ... -delete" के वर्कअराउंड का उपयोग करता हूं, लेकिन वे "find ... -delete" की तुलना में बहुत धीमे हो सकते हैं। मैंने "find ..." देखा है। एक NFS फाइलसिस्टम पर गहरी निर्देशिकाओं पर "-exec rm {} +" की तुलना में "5x अधिक तेज" चलाएं।

'-नॉट पाथ' सॉल्यूशन में अपवर्जित निर्देशिकाओं में और नीचे सभी फाइलों को देखने का स्पष्ट ओवरहेड है।

"खोजें .. -exec rm {} +" कॉल rm जो सिस्टम कॉल करता है:

fstatat(AT_FDCWD, path...); 
unlinkat(AT_FDCWD, path, 0)

"ढूँढें -delete" सिस्टम कॉल करता है:

 fd=open(dir,...);
 fchdir(fd); 
 fstatat(AT_FDCWD, filename,...)
 unlinkat(dirfd, filename,...)

तो "-exec rm {} +" + rm कमांड इनकोड लुकअप को प्रति फ़ाइल दो बार प्रति फ़ाइल करने के लिए पूर्ण पथ करता है, लेकिन "फाइंड -डेलीट" एक डायरेक्टरी करता है और वर्तमान निर्देशिका में फ़ाइल नाम को हटाता है। यह एक बड़ी जीत है जब आप एक निर्देशिका में बहुत सारी फाइलें निकाल रहे हैं।

(क्षमा करें) (क्षमा करें)

ऐसा लगता है कि बीच-बीच में डिज़ाइन का डिज़ाइन -depth, -delete और -prune अनावश्यक रूप से सामान्य क्रिया करने के सबसे कुशल तरीके को समाप्त करता है "उन-डायरेक्ट्री निर्देशिका को छोड़कर फ़ाइलों को हटाएं"

"-Type f -delete" का संयोजन बिना -depth के चलने में सक्षम होना चाहिए क्योंकि यह निर्देशिकाओं को हटाने का प्रयास नहीं कर रहा है। वैकल्पिक रूप से, यदि "खोज" में "-डेलीटाइल" कार्रवाई होती है जो कहती है कि निर्देशिकाओं को हटाएं नहीं, -depth को निहित होने की आवश्यकता नहीं होगी।

यदि rm के पास फ़ाइल नाम, ओपन डाइरेक्टरीज़ को सॉर्ट करने और पूर्ण पथ को अनलिंक करने के बजाय अनलिंकट (dir_fd, फ़ाइलनाम) करने का विकल्प होता है, तो rm कमांड के xargs या find -exec कॉल्स को बंद किया जा सकता है। यह पहले से ही अनलिंकट (dir_fd, फ़ाइल नाम) करता है जब -r विकल्प के साथ निर्देशिकाओं के माध्यम से पुनरावृत्ति करता है।

(व्हाइन मोड ऑफ)

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