कमांड का उपयोग करें, लेकिन दो निर्देशिकाओं में फ़ाइलों को बाहर करें


86

मैं उन फ़ाइलों को ढूंढना चाहता हूं जो अंत में हैं _peaks.bed, लेकिन फ़ोल्डर्स tmpऔर scriptsफ़ोल्डर्स में फ़ाइलों को बाहर करें ।

मेरी आज्ञा इस प्रकार है:

 find . -type f \( -name "*_peaks.bed" ! -name "*tmp*" ! -name "*scripts*" \)

लेकिन यह काम नहीं किया। फ़ाइल tmpऔर scriptफ़ोल्डर अभी भी प्रदर्शित किए जाएंगे।

क्या किसी को इस बारे में विचार है?

जवाबों:


189

यहां बताया गया है कि आप इसे कैसे निर्दिष्ट कर सकते हैं find:

find . -type f -name "*_peaks.bed" ! -path "./tmp/*" ! -path "./scripts/*"

स्पष्टीकरण:

  • find . - वर्तमान कार्य निर्देशिका (डिफ़ॉल्ट रूप से पुनरावर्ती) से प्रारंभ करें
  • -type f- यह निर्दिष्ट करें findकि आप परिणामों में केवल फाइलें चाहते हैं
  • -name "*_peaks.bed" - नाम समाप्त होने वाली फ़ाइलों की तलाश करें _peaks.bed
  • ! -path "./tmp/*" - उन सभी परिणामों को छोड़ दें जिनकी राह से शुरू होती है ./tmp/
  • ! -path "./scripts/*" - उन सभी परिणामों को भी छोड़ दें जिनकी राह शुरू होती है ./scripts/

समाधान का परीक्षण:

$ mkdir a b c d e
$ touch a/1 b/2 c/3 d/4 e/5 e/a e/b
$ find . -type f ! -path "./a/*" ! -path "./b/*"

./d/4
./c/3
./e/a
./e/b
./e/5

आप बहुत करीब थे, -nameविकल्प केवल बेसन पर विचार करता है, जहां -pathपूरे पथ पर विचार करता है =)


अच्छा काम। हालाँकि, आप ओपी के लिए वांछित चीजों में से एक को भूल गए, जिसके साथ फाइल समाप्त हो रही थी _peaks.bed
एलेक्स

2
यह GNU में कई एक्सटेंशन का उपयोग करता है find, लेकिन चूंकि प्रश्न लिनक्स को टैग किया गया है, इसलिए यह कोई समस्या नहीं है। अच्छा उत्तर।
जोनाथन लेफ्लर

1
एक छोटा नोट: यदि आप .अपने प्रारंभिक खोज संकेत पर उपयोग करते हैं, तो आपको इसे प्रत्येक उस पथ पर उपयोग करना होगा जिसे आप बाहर करते हैं। पथ मिलान बहुत सख्त है, यह फजी खोज नहीं करता है। तो अगर आप इसका उपयोग find / -type f -name *.bed" ! -path "./tmp/"काम नहीं करने जा रहे हैं। आपको ! -path "/tmp"इसे खुश करने की आवश्यकता है ।
२०:०२ पर पीलमैन

3
यह ध्यान रखना महत्वपूर्ण है कि * महत्वपूर्ण है। $ ! -path "./directory/*"
थॉमस बेनेट

3
मैन पेजों के अनुसार: "पूरी डायरेक्टरी ट्री को नजरअंदाज करने के लिए, ट्री -pruneकी हर फाइल को चेक करने की बजाए इस्तेमाल करें ।" यदि आपकी बहिष्कृत निर्देशिका बहुत गहरी चलती है या आपके पास बहुत सारी फाइलें हैं और आप प्रदर्शन की परवाह करते हैं, तो -pruneइसके बजाय विकल्प का उपयोग करें ।
30

8

यहाँ एक तरीका है जो आप इसे कर सकते हैं ...

find . -type f -name "*_peaks.bed" | egrep -v "^(./tmp/|./scripts/)"

2
इसमें findकेवल GNU के बजाय किसी भी संस्करण के साथ काम करने का गुण है find। हालाँकि, प्रश्न लिनक्स को टैग किया गया है ताकि यह महत्वपूर्ण न हो।
जोनाथन लेफ्लर

2

उपयोग

find \( -path "./tmp" -o -path "./scripts" \) -prune -o  -name "*_peaks.bed" -print

या

find \( -path "./tmp" -o -path "./scripts" \) -prune -false -o  -name "*_peaks.bed"

या

find \( -path "./tmp" -path "./scripts" \) ! -prune -o  -name "*_peaks.bed"

आदेश महत्वपूर्ण है। यह बाएं से दाएं का मूल्यांकन करता है। हमेशा पथ बहिष्करण के साथ शुरू करें।

व्याख्या

पूरी निर्देशिका को बाहर करने के लिए -not(या !) का उपयोग न करें । का उपयोग करें -prune। जैसा कि मैनुअल में बताया गया है:

−prune    The primary shall always evaluate as  true;  it
          shall  cause  find  not  to descend the current
          pathname if it is a directory.  If  the  −depth
          primary  is specified, the −prune primary shall
          have no effect.

और GNU में मैनुअल खोजें:

-path pattern
              [...]
              To ignore  a  whole
              directory  tree,  use  -prune rather than checking
              every file in the tree.

वास्तव में, यदि आप उपयोग करते हैं, तो -not -path "./pathname"प्रत्येक नोड के लिए अभिव्यक्ति का मूल्यांकन करेंगे "./pathname"

अभिव्यक्तियाँ केवल स्थिति मूल्यांकन हैं।

  • \( \)- समूह संचालन (आप उपयोग कर सकते हैं -path "./tmp" -prune -o -path "./scripts" -prune -o, लेकिन यह अधिक क्रिया है)।
  • -path "./script" -prune- अगर यह -pathसच है और एक निर्देशिका है, तो उस निर्देशिका के लिए सही लौटें और उसमें उतरें।
  • -path "./script" ! -prune- यह मूल्यांकन करता है (-path "./script") AND (! -prune)। यह हमेशा असत्य के लिए "हमेशा सच" का संकेत देता है। यह "./script"एक मैच के रूप में मुद्रण से बचा जाता है ।
  • -path "./script" -prune -false- के बाद से -pruneहमेशा सच देता है, आप इसे का पालन कर सकते के साथ -falseकी तुलना में भी ऐसा ही करने !
  • -o- या लिमिटेड। यदि कोई ऑपरेटर दो अभिव्यक्तियों के बीच निर्दिष्ट नहीं है, तो यह AND ऑपरेटर के लिए चूक है।

इसलिए, \( -path "./tmp" -o -path "./scripts" \) -prune -o -name "*_peaks.bed" -printइसका विस्तार किया जाता है:

[ (-path "./tmp" OR -path "./script") AND -prune ] OR ( -name "*_peaks.bed" AND print )

यहां प्रिंट महत्वपूर्ण है क्योंकि इसके बिना इसका विस्तार किया गया है:

{ [ (-path "./tmp" OR -path "./script" )  AND -prune ]  OR (-name "*_peaks.bed" ) } AND print

-printको खोजने के द्वारा जोड़ा जाता है - यही कारण है कि ज्यादातर समय, आपको इसे अभिव्यक्ति में जोड़ने की आवश्यकता नहीं है। और चूंकि -pruneयह सही है, यह "./script" और "./tmp" प्रिंट करेगा।

दूसरों में यह आवश्यक नहीं है क्योंकि हम -pruneहमेशा झूठे लौटने के लिए स्विच करते हैं।

संकेत: आप find -D opt expr 2>&1 1>/dev/nullयह देखने के लिए उपयोग कर सकते हैं कि यह कैसे अनुकूलित और विस्तारित किया गया है,
find -D search expr 2>&1 1>/dev/nullयह देखने के लिए कि किस पथ की जाँच की गई है।


0

कुछ ऐसा आजमाएं

find . \( -type f -name \*_peaks.bed -print \) -or \( -type d -and \( -name tmp -or -name scripts \) -and -prune \)

और अगर मुझे यह थोड़ा गलत लगा तो बहुत आश्चर्य नहीं होगा। यदि लक्ष्य एक निष्पादन (प्रिंट के बजाय) है, तो इसे स्थान पर प्रतिस्थापित करें।


0

मेरे लिए, इस समाधान ने खोज के साथ कमांड निष्पादन पर काम नहीं किया, वास्तव में पता नहीं क्यों, इसलिए मेरा समाधान है

find . -type f -path "./a/*" -prune -o -path "./b/*" -prune -o -exec gzip -f -v {} \;

स्पष्टीकरण: के समान के साथ sampson-chen के समान

-प्रत्यक्ष - प्रक्रिया पथ की उपेक्षा करें ...

-o - फिर यदि कोई मिलान परिणाम प्रिंट नहीं करता है, (निर्देशिकाओं को प्रीइन करें और शेष परिणाम प्रिंट करें)

18:12 $ mkdir a b c d e
18:13 $ touch a/1 b/2 c/3 d/4 e/5 e/a e/b
18:13 $ find . -type f -path "./a/*" -prune -o -path "./b/*" -prune -o -exec gzip -f -v {} \;

gzip: . is a directory -- ignored
gzip: ./a is a directory -- ignored
gzip: ./b is a directory -- ignored
gzip: ./c is a directory -- ignored
./c/3:    0.0% -- replaced with ./c/3.gz
gzip: ./d is a directory -- ignored
./d/4:    0.0% -- replaced with ./d/4.gz
gzip: ./e is a directory -- ignored
./e/5:    0.0% -- replaced with ./e/5.gz
./e/a:    0.0% -- replaced with ./e/a.gz
./e/b:    0.0% -- replaced with ./e/b.gz

स्वीकृत उत्तर काम नहीं आया, लेकिन यह काम करता है। , छँटाई का उपयोग करना find . -path ./scripts -prune -name '*_peaks.bed' -type f। सुनिश्चित नहीं है कि कई निर्देशिकाओं को कैसे हटाया जाए। यह typeनिर्दिष्ट किए जाने के बावजूद शीर्ष स्तर से बाहर की निर्देशिका को भी सूचीबद्ध करता है। ग्रेप के माध्यम से छोड़कर अधिक सीधा लगता है जब तक कि आप खोज ऑपरेशन को गति देने के लिए प्रून का उपयोग नहीं करना चाहते।
मोहनीश

मुझे कई निर्देशिकाओं को छोड़कर भी परेशानी हुई, लेकिन ऊपर की टिप्पणियों ने मुझे एक जवाब दिया जो काम किया। मैं '-not -path' के कई उदाहरणों का उपयोग करता हूं और प्रत्येक पथ अभिव्यक्ति में मैं पूर्ण उपसर्ग को शामिल करता हूं जैसा कि पहले पैरामीटर में 'खोजने' के लिए उपयोग किया जाता है और प्रत्येक को तारांकन (और किसी भी बिंदु से बच) के साथ समाप्त होता है।
जेटसेट

0

आप नीचे कोशिश कर सकते हैं:

find ./ ! \( -path ./tmp -prune \) ! \( -path ./scripts -prune \) -type f -name '*_peaks.bed'

2
इस तरह के एक पुराने प्रश्न पर (4 वर्ष!) आप यह बताना चाहते हैं कि यह नया उत्तर बेहतर या अलग क्यों है, न कि केवल "डंप" कोड।
निक
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.