श में 'खोज' के '-प्र्यून' विकल्प का उपयोग कैसे करें?


219

मुझे दिए गए उदाहरण से बहुत समझ नहीं है man find, क्या कोई मुझे कुछ उदाहरण और स्पष्टीकरण दे सकता है? क्या मैं इसमें नियमित अभिव्यक्ति को जोड़ सकता हूं?


अधिक विस्तृत प्रश्न इस प्रकार है:

एक शेल स्क्रिप्ट लिखें changeall, जिसमें एक इंटरफ़ेस हो changeall [-r|-R] "string1" "string2"। यह का एक प्रत्यय के साथ सभी फ़ाइलों को मिलेगा .h, .C, .cc, या .cppऔर की सभी घटनाओं को बदलने string1के लिए string2-rकेवल वर्तमान डायर में रहने के लिए या उप-विभाग सहित के लिए विकल्प है।

ध्यान दें:

  1. गैर-पुनरावर्ती मामले के लिए, lsअनुमति नहीं है, हम केवल उपयोग कर सकते हैं findऔर sed
  2. मैंने कोशिश की find -depthलेकिन यह समर्थित नहीं था। इसलिए मैं सोच रहा था कि क्या -pruneमदद मिल सकती है, लेकिन उदाहरण से समझ नहीं आया man find

EDIT2: मैं असाइनमेंट कर रहा था, मैंने महान विवरणों में सवाल नहीं पूछा क्योंकि मैं इसे खुद खत्म करना चाहूंगा। चूंकि मैंने पहले ही इसे कर लिया था और इसे हाथ में ले लिया था, अब मैं पूरे प्रश्न को बता सकता हूं। इसके अलावा, मैं उपयोग किए बिना काम पूरा करने में कामयाब रहा -prune, लेकिन इसे वैसे भी सीखना चाहूंगा।

जवाबों:


438

मैं जिस चीज़ के बारे -pruneमें भ्रमित हो रहा था , वह यह है कि यह एक क्रिया है (जैसे -print), टेस्ट नहीं (जैसे -name)। यह "टू-डू" सूची को बदल देता है, लेकिन हमेशा सच होता है

उपयोग करने के लिए सामान्य पैटर्न -pruneयह है:

find [path] [conditions to prune] -prune -o \
            [your usual conditions] [actions to perform]

आप बहुत हमेशा -o(तार्किक OR) तुरंत चाहते हैं -prune, क्योंकि परीक्षण का पहला भाग (अप करने के लिए और शामिल है -prune) उस सामान के लिए जो आप वास्तव में चाहते हैं (यानी: वह सामान जिसे आप चुभाना नहीं चाहते हैं) के लिए गलत वापस आ जाएगा ।

यहाँ एक उदाहरण है:

find . -name .snapshot -prune -o -name '*.foo' -print

यह "* .foo" फ़ाइलों को ".snapshot" निर्देशिकाओं के अंतर्गत नहीं मिलेगा। इस उदाहरण में, -name .snapshotबनाता है [conditions to prune], और -name '*.foo' -printहै [your usual conditions]और है [actions to perform]

महत्वपूर्ण नोट :

  1. यदि आप सब करना चाहते हैं, तो उन परिणामों को प्रिंट करें जिन्हें आप -printकार्रवाई छोड़ने के लिए उपयोग कर सकते हैं । आप आम तौर पर उपयोग करते समय ऐसा नहीं करना चाहते हैं -prune

    खोज का डिफ़ॉल्ट व्यवहार कार्रवाई के साथ "और" पूरी अभिव्यक्ति -printहै अगर -pruneअंत में (विडंबना) के अलावा कोई कार्रवाई नहीं होती है। इसका मतलब है कि यह लिखना:

    find . -name .snapshot -prune -o -name '*.foo'              # DON'T DO THIS

    यह लिखने के बराबर है:

    find . \( -name .snapshot -prune -o -name '*.foo' \) -print # DON'T DO THIS

    जिसका अर्थ है कि यह उस निर्देशिका का नाम भी प्रिंट कर देगा जिसे आप प्रून कर रहे हैं, जो आमतौर पर वह नहीं है जो आप चाहते हैं। इसके बजाय -printयदि आप चाहते हैं तो स्पष्ट रूप से कार्रवाई को निर्दिष्ट करना बेहतर है :

    find . -name .snapshot -prune -o -name '*.foo' -print       # DO THIS
  2. यदि आपकी "सामान्य स्थिति" उन फ़ाइलों से मेल खाने के लिए होती है जो आपकी prune स्थिति से मेल खाती हैं, तो उन फ़ाइलों को आउटपुट में शामिल नहीं किया जाएगा । इसे ठीक करने का तरीका यह है कि आप -type dअपनी prune स्थिति में एक विधेय जोड़ें ।

    उदाहरण के लिए, मान लें कि हम किसी भी डायरेक्टरी को शुरू करना चाहते थे, जो .git(यह माना जाता है कि कुछ हद तक वंचित है - आम तौर पर आपको केवल नाम की चीज को हटाने की आवश्यकता होती है .git ), लेकिन इसके अलावा अन्य सभी फाइलों को देखना चाहते थे, जैसे फाइलें .gitignore। आप यह कोशिश कर सकते हैं:

    find . -name '.git*' -prune -o -type f -print               # DON'T DO THIS

    यह आउटपुट में शामिल नहीं होगा .gitignore। यहाँ निश्चित संस्करण है:

    find . -name '.git*' -type d -prune -o -type f -print       # DO THIS

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


6
यह आपके टेक्स्ट में 100% स्पष्ट नहीं है (लेकिन जैसा कि आप केवल '* .foo' प्रिंट करते हैं, यह संघर्ष नहीं करता है), लेकिन -प्र्यून भाग "ssapapshot" नाम के कुछ भी (न केवल निर्देशिका) प्रिंट नहीं करेगा। यानी, -pruneकेवल निर्देशिकाओं पर काम नहीं करता है (लेकिन, निर्देशिकाओं के लिए, यह उस स्थिति से मेल खाते निर्देशिकाओं को दर्ज करने से भी रोकता है, अर्थात यहाँ मिलानों को मिलान करता है -name .snapshot)।
ओलिवियर दुलक

12
और अच्छी तरह से किए गए स्पष्टीकरण (और विशेष रूप से महत्वपूर्ण नोट) के लिए आपके लिए +1। आपको इसे ढूंढने वालों को प्रस्तुत करना चाहिए (जैसा कि सामान्य मानव के लिए मैन पेज "प्रून" की व्याख्या नहीं करता है ^ ^ मुझे यह पता लगाने की कई कोशिशें हुईं, और मैंने यह नहीं देखा कि साइड इफेक्ट आपको हमारे बारे में चेतावनी देता है)
ओलिवियर दुलक

2
@OlivierDulac संभावित स्ट्रिपिंग फ़ाइलों के बारे में एक बहुत अच्छा बिंदु है जिसे आप रखना चाहते हैं। मैंने इसे स्पष्ट करने के लिए उत्तर को अपडेट कर दिया है। यह वास्तव में -pruneस्वयं नहीं है जो इस कारण से, वैसे भी है। मुद्दा यह है कि या ऑपरेटर "शॉर्ट-सर्किट" है, और इसकी तुलना में कम पूर्वता है और। अंतिम परिणाम यह है कि अगर किसी फ़ाइल को कहा जाता .snapshotहै -name, -pruneतो वह पहले से मेल खाएगी , फिर कुछ भी नहीं करेगी (लेकिन सच लौटाएगी), और तब या वापस लौटा सत्य तब से है जब तक उसका वाम-तर्क सही नहीं था। कार्रवाई (जैसे:) -printइसके दूसरे तर्क का हिस्सा है, इसलिए इसे निष्पादित करने का कभी मौका नहीं मिलता है।
लॉरेंस गोंसाल्वेस

3
+1 अंत में पता चला कि मुझे -printअंत में इसकी आवश्यकता क्यों है , मैं अब \! -path <pattern>इसके अलावा जोड़ना बंद कर सकता हूं-prune
दुस्साहसी परिवर्तनीय

6
ध्यान दें कि "-o" "-or" के लिए शॉर्टहैंड है, जो (जबकि POSIX- अनुरूप नहीं) अधिक स्पष्ट रूप से पढ़ता है।
योयो

27

आम तौर पर हम जिस मूल तरीके से चीजों को लाइनेक्स में करते हैं और जिस तरह से सोचते हैं वह बाएं से दाएं होता है।
तो आप जाकर लिखेंगे कि आप पहले क्या देख रहे हैं:

find / -name "*.php"

तब आप शायद एंट्री मारते हैं और महसूस करते हैं कि आपको निर्देशिकाओं से बहुत अधिक फाइलें मिल रही हैं, जिन्हें आप नहीं करना चाहते हैं। अपने माउंट किए गए ड्राइव को खोजने से बचने के लिए / मीडिया को बाहर करें।
अब आपको पिछली कमांड के लिए बस एपीपीडीएन करना चाहिए:

-print -o -path '/media' -prune

तो अंतिम आदेश है:

find / -name "*.php" -print -o -path '/media' -prune

............... | <--- शामिल करें ---> | .................... | <- -------- बहिष्कृत ---------> |

मुझे लगता है कि यह संरचना बहुत आसान है और सही दृष्टिकोण से संबंधित है


3
मैंने यह उम्मीद नहीं की होगी कि यह कुशल होगा - मैंने सोचा होगा कि यह प्रून से पहले लेफ्ट क्लॉज का मूल्यांकन करेगा, लेकिन मेरे आश्चर्य की बात यह findहै कि एक त्वरित परीक्षण से लगता है कि यह -pruneक्लॉज को प्रोसेस करने के लिए काफी चतुर है । हम्म, दिलचस्प।
Artfulrobot

मैंने कभी इस पर विचार नहीं किया था कि लगभग एक दशक में जीएनयू का उपयोग किया गया है! उसके लिये आपका धन्यवाद! यह निश्चित रूप से मेरे सोचने के तरीके को बदल देगा -prune
फेलिप अल्वारेज

3
@artfulrobot क्या यह वास्तव में पहले इसे प्रोसेस कर रहा है? मैंने सोचा होगा कि यह प्रवेश कर रहा है /media, यह देखते हुए कि इसे नहीं बुलाया गया है *.phpऔर फिर जाँच कर रहा है कि क्या यह वर्तमान में अंदर है /media, यह देखते हुए कि यह है और इसलिए उस पूरे उपशीर्षक को छोड़ रहा है। यह अभी भी बाएं से दाएं है, यह तब तक कोई फर्क नहीं पड़ता जब तक दोनों चेक ओवरलैप नहीं होते।
phk

26

खबरदार है कि -prune किसी भी निर्देशिका में उतरने से नहीं रोकता है जैसा कि कुछ ने कहा है। यह उन निर्देशिकाओं में उतरने से रोकता है जो उस परीक्षण से मेल खाती हैं जिस पर इसे लागू किया गया है। शायद कुछ उदाहरण मदद करेंगे (एक रेगेक्स उदाहरण के लिए नीचे देखें)। यह इतना लंबा होने के लिए खेद है।

$ find . -printf "%y %p\n"    # print the file type the first time FYI
d .
f ./test
d ./dir1
d ./dir1/test
f ./dir1/test/file
f ./dir1/test/test
d ./dir1/scripts
f ./dir1/scripts/myscript.pl
f ./dir1/scripts/myscript.sh
f ./dir1/scripts/myscript.py
d ./dir2
d ./dir2/test
f ./dir2/test/file
f ./dir2/test/myscript.pl
f ./dir2/test/myscript.sh

$ find . -name test
./test
./dir1/test
./dir1/test/test
./dir2/test

$ find . -prune
.

$ find . -name test -prune
./test
./dir1/test
./dir2/test

$ find . -name test -prune -o -print
.
./dir1
./dir1/scripts
./dir1/scripts/myscript.pl
./dir1/scripts/myscript.sh
./dir1/scripts/myscript.py
./dir2

$ find . -regex ".*/my.*p.$"
./dir1/scripts/myscript.pl
./dir1/scripts/myscript.py
./dir2/test/myscript.pl

$ find . -name test -prune -regex ".*/my.*p.$"
(no results)

$ find . -name test -prune -o -regex ".*/my.*p.$"
./test
./dir1/test
./dir1/scripts/myscript.pl
./dir1/scripts/myscript.py
./dir2/test

$ find . -regex ".*/my.*p.$" -a -not -regex ".*test.*"
./dir1/scripts/myscript.pl
./dir1/scripts/myscript.py

$ find . -not -regex ".*test.*"                   .
./dir1
./dir1/scripts
./dir1/scripts/myscript.pl
./dir1/scripts/myscript.sh
./dir1/scripts/myscript.py
./dir2

अगर आप "टच ./dir1/scripts/test" (यानी, एक "परीक्षण" फ़ाइल है, और डीआईआर नहीं है, उस मुद्रित सबडिर में), यह प्रिंट नहीं होगा find . -name test -prune -o -print: iow, -pruneएक क्रिया है फ़ाइलों पर काम करता है
ओलिवियर दुलैक

10

अन्य उत्तरों में दी गई सलाह को जोड़ना (मेरे पास उत्तर बनाने के लिए कोई प्रतिनिधि नहीं है) ...

-pruneअन्य अभिव्यक्तियों के साथ संयोजन करते समय, व्यवहार में एक सूक्ष्म अंतर होता है जिसके आधार पर अन्य अभिव्यक्तियों का उपयोग किया जाता है।

@ लॉरेंस गोन्साल्व्स के उदाहरण में "* .foo" फाइलें मिलेंगी जो ".snapshot" निर्देशिका के अंतर्गत नहीं हैं: -

find . -name .snapshot -prune -o -name '*.foo' -print

हालाँकि, यह थोड़ा अलग हाथ है, शायद अनजाने में, .snapshotनिर्देशिका (और किसी भी नेस्टेड .snapshot निर्देशिका) को भी सूचीबद्ध करें : -

find . -name .snapshot -prune -o -name '*.foo'

इसका कारण है (मेरे सिस्टम पर पेज के अनुसार): -

यदि दी गई अभिव्यक्ति में कोई प्राइमेरी -exec, -ls, -ok, या -प्रिंट नहीं है, तो दी गई अभिव्यक्ति प्रभावी रूप से इसके द्वारा है:

(दिए गए_प्रकरण) -प्रकरण

अर्थात्, दूसरा उदाहरण निम्नलिखित में प्रवेश करने के बराबर है, जिससे शब्दों का समूहन संशोधित होता है: -

find . \( -name .snapshot -prune -o -name '*.foo' \) -print

यह कम से कम सोलारिस 5.10 पर देखा गया है। लगभग 10 वर्षों के लिए * निक्स के विभिन्न स्वादों का उपयोग करने के बाद, मैंने हाल ही में एक कारण के लिए खोज की है कि ऐसा क्यों होता है।


-pruneसाथ और बिना उपयोग के बीच के अंतर पर ध्यान देने के लिए धन्यवाद -print!
एमसीडब्ल्यू

3

Prune एक निर्देशिका स्विच पर पुनरावृत्ति नहीं है।

मैन पेज से

अगर -depth नहीं दिया गया है, सच है; यदि फ़ाइल एक निर्देशिका है, तो उसमें न उतरें। अगर -depth दिया गया है, झूठा; कोई प्रभाव नहीं।

मूल रूप से यह किसी भी उप निर्देशिका में नहीं आएगा।

इस उदाहरण को लें:

आपके पास निम्न निर्देशिकाएं हैं

  • / घर / test2
  • / घर / test2 / test2

यदि आप चलाते हैं find -name test2:

यह दोनों निर्देशिकाओं को लौटाएगा

यदि आप चलाते हैं find -name test2 -prune:

यह केवल / घर / टेस्ट 2 लौटेगा क्योंकि यह / होम / टेस्ट 2 में नहीं उतरेगा / घर / टेस्ट 2 / टेस्ट 2


100% सच नहीं है: यह "है जब मिलान की स्थिति में छंटाई करते हैं, और यदि यह एक निर्देशिका है, तो इसे टू-डू सूची से बाहर ले जाएं, अर्थात इसे दर्ज न करें"। -प्र्यून फाइलों पर भी काम करता है।
ओलिवियर दुलैक

2

मैं इस पर कोई विशेषज्ञ नहीं हूं (और यह पृष्ठ http://mywiki.wooledge.org/UsingFind के साथ बहुत उपयोगी था )

बस देखा -pathएक ऐसे रास्ते के लिए है जो पूरी तरह से स्ट्रिंग / पथ से मेल खाता है, जोfind ( .थिसिस उदाहरणों में) बस के बाद आता है जहां -nameसभी बेसन से मेल खाता है।

find . -path ./.git  -prune -o -name file  -print

अपनी वर्तमान निर्देशिका में .गित निर्देशिका को ब्लॉक करें ( अपनी खोज के अनुसार . )

find . -name .git  -prune -o -name file  -print

सभी .it उपनिर्देशिकाओं को पुनरावर्ती रूप से ब्लॉक करता है।

नोट ./ बेहद जरूरी है !! -pathकिसी एंकर से . या जो कुछ भी आता है, उसका मिलान करना चाहिए, अगर आपको उसके बाहर से मैच मिलते हैं (या दूसरी तरफ से -o) 'शायद वहाँ छंटाई नहीं हो रही है!' मैं इस बात से अनभिज्ञ था और इसने मुझे -थ का उपयोग करने के लिए डाल दिया जब यह महान है जब आप एक ही बेसन के साथ सभी उपनिर्देशिका को prune नहीं करना चाहते हैं: डी


ध्यान दें कि यदि आपका ऐसा कहना है find bla/तो आपको -पैथ .it की आवश्यकता होगी bla/(या यदि आप *इसके बजाय सामने की ओर चमकते हैं तो यह अधिक समान व्यवहार करेगा)
sabgenton

1

Dir सहित सब कुछ दिखाएँ, लेकिन इसकी लंबी बोरिंग सामग्री नहीं:

find . -print -name dir -prune

0

यदि आप सभी अच्छे उत्तरों को यहाँ पढ़ते हैं तो मेरी समझ यह है कि निम्नलिखित सभी एक ही परिणाम देते हैं:

find . -path ./dir1\*  -prune -o -print

find . -path ./dir1  -prune -o -print

find . -path ./dir1\*  -o -print
#look no prune at all!

लेकिन अंतिम एक बहुत लंबा समय लगेगा क्योंकि यह अभी भी dir1 में सब कुछ खोजता है। मुझे लगता है कि असली सवाल यह है कि -orवास्तव में उन्हें खोजे बिना अवांछित परिणामों को बाहर कैसे किया जाए।

इसलिए मुझे लगता है कि प्रून का मतलब पिछले मैचों से अच्छा नहीं है लेकिन इसे चिह्नित करें ...

http://www.gnu.org/software/findutils/manual/html_mono/find.html "यह हालांकि '-प्र्यून' कार्रवाई के प्रभाव के कारण नहीं है (जो केवल आगे वंश को रोकता है, यह सुनिश्चित नहीं करता है हम उस आइटम को अनदेखा करते हैं) इसके बजाय, यह प्रभाव '-o' के उपयोग के कारण होता है। चूँकि "या" स्थिति के बाएं हाथ की स्थिति सफल हुई है ।/src/emacs, यह सही मूल्यांकन करने के लिए आवश्यक नहीं है- इस विशेष फ़ाइल के लिए हैंड-साइड ('-प्रिंट')।


0

findफ़ाइलों की एक सूची बनाता है। यह आपके द्वारा प्रत्येक को प्रदान की गई विधेय को लागू करता है और जो पास करता है उसे वापस करता है।

यह विचार जिसका -pruneअर्थ है कि परिणामों से बाहर रखा जाना वास्तव में मेरे लिए भ्रमित करने वाला था। आप बिना किसी फ़ाइल को बाहर निकाल सकते हैं:

find -name 'bad_guy' -o -name 'good_guy' -print  // good_guy

सभी -pruneखोज का व्यवहार बदल रहा है। यदि वर्तमान मैच एक निर्देशिका है, तो यह कहता है "हे find, वह फ़ाइल जो आपने अभी-अभी मेल की है, न ही उसमें उतरें" । यह सिर्फ खोज के लिए फाइलों की सूची से उस पेड़ (लेकिन खुद फ़ाइल नहीं) को हटा देता है।

इसका नाम होना चाहिए -dont-descend


0

काफी कुछ उत्तर हैं; उनमें से कुछ थोड़ा बहुत सिद्धांत-भारी हैं। मैं छोड़ देता हूँ कि मुझे एक बार प्रून की आवश्यकता थी इसलिए शायद किसी की पहली-पहली / उदाहरण की तरह की व्याख्या उपयोगी हो। :)

संकट

मेरे पास लगभग 20 नोड निर्देशिकाओं वाला एक फ़ोल्डर था, जिसमें से प्रत्येक को अपनी node_modulesनिर्देशिका अपेक्षित थी।

एक बार जब आप किसी परियोजना में आते हैं, तो आप प्रत्येक को देखते हैं ../node_modules/module। लेकिन आप जानते हैं कि यह कैसा है। लगभग हर मॉड्यूल में निर्भरताएं होती हैं, इसलिए आप जो देख रहे हैं वह अधिक पसंद हैprojectN/node_modules/moduleX/node_modules/moduleZ...

मैं निर्भरता की निर्भरता के साथ एक सूची के साथ डूबना नहीं चाहता था ...

जानना -d n/ जानना -depth n, यह मेरी मदद नहीं करता था, क्योंकि मुख्य / पहला नोड_मॉडल निर्देशिका मैं चाहता था कि प्रत्येक परियोजना एक अलग गहराई पर थी, जैसे:

Projects/MysuperProjectName/project/node_modules/...
Projects/Whatshisname/version3/project/node_modules/...
Projects/project/node_modules/...
Projects/MysuperProjectName/testProject/november2015Copy/project/node_modules/...
[...]

मैं पहली बार समाप्त होने वाले रास्तों की सूची कैसे प्राप्त कर सकता हूं node_modulesऔर उसी को प्राप्त करने के लिए अगली परियोजना पर जा सकता हूं ?

दर्ज -prune

जब आप जोड़ते हैं -prune, तब भी आपके पास मानक पुनरावर्ती खोज होगी। प्रत्येक "पथ" का विश्लेषण किया जाता है, और हर खोज को थूक दिया जाता है और findएक अच्छे अध्याय की तरह खोदता रहता है। लेकिन यह अधिक खोदना है node_modulesजो मैं नहीं चाहता था।

तो, अंतर यह है कि उन लोगों के अलग अलग रास्तों के किसी भी, है -pruneजाएगा findजब वह अपने आइटम मिल गया है और नीचे उस विशेष अवसर खुदाई को रोकने के लिए। मेरे मामले में, node_modulesफ़ोल्डर।

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