जब यूनिक्स / लिनेक्स शेल में पैटर्न का मिलान होता है तो मैं उलटा या नकारात्मक वाइल्डकार्ड का उपयोग कैसे कर सकता हूं?


325

मान लें कि मैं फ़ाइलों और फ़ोल्डरों को छोड़कर एक निर्देशिका की सामग्री को कॉपी करना चाहता हूं जिनके नाम में 'संगीत' शब्द है।

cp [exclude-matches] *Music* /target_directory

इसे पूरा करने के लिए [बहिष्कृत मैचों] के स्थान पर क्या जाना चाहिए?

जवाबों:


375

बैश में आप यह सक्षम करने से क्या कर सकते हैं extglobइस तरह, विकल्प (की जगह lsके साथ cpऔर लक्ष्य निर्देशिका जोड़ने के लिए, निश्चित रूप से)

~/foobar> shopt extglob
extglob        off
~/foobar> ls
abar  afoo  bbar  bfoo
~/foobar> ls !(b*)
-bash: !: event not found
~/foobar> shopt -s extglob  # Enables extglob
~/foobar> ls !(b*)
abar  afoo
~/foobar> ls !(a*)
bbar  bfoo
~/foobar> ls !(*foo)
abar  bbar

आप बाद में extglob को अक्षम कर सकते हैं

shopt -u extglob

14
मुझे यह सुविधा पसंद है:ls /dir/*/!(base*)
एरिक रॉबर्टसन

6
आप सब कुछ कैसे शामिल करते हैं ( ) और बाहर भी? (बी )
एलिजा लिन

4
आप मैच को कैसे कहेंगे, सब कुछ f, को छोड़कर, के साथ शुरू होगा foo?
नोल्डोरिन

8
यह डिफ़ॉल्ट रूप से अक्षम क्यों है?
वेबर 2

3
shopt -o -u histexpand यदि आपको उनमें विस्मयादिबोधक बिंदुओं वाली फ़ाइलों को देखने की आवश्यकता है - डिफ़ॉल्ट रूप से, एक्स्ग्लोब डिफ़ॉल्ट रूप से बंद है, ताकि यह हिस्टैक्सैंड के साथ हस्तक्षेप न करे, डॉक्स में यह बताता है कि ऐसा क्यों है। foo के अलावा f के साथ शुरू होने वाली हर चीज़ से मेल खाएँ: f (oo), बेशक 'food' अभी भी मेल खाता होगा (आपको 'foo' में शुरू होने वाली चीज़ों को रोकने के लिए f (oo *) की ज़रूरत होगी या, अगर आप छुटकारा पाना चाहते हैं! '.foo' के उपयोग ( .foo) में समाप्त होने वाली कुछ चीज़ें , या उपसर्ग: myprefix (( .foo) (myprefixBLAH से मेल खाती है, लेकिन myprefixBLAH.foo से मेल नहीं खाती)
osirisgothic

227

extglobखोल विकल्प आपको कमांड लाइन में और अधिक शक्तिशाली पैटर्न मिलान देता है।

आप इसे चालू करते हैं shopt -s extglob, और इसे बंद कर देते हैं shopt -u extglob

अपने उदाहरण में, आप शुरू में करेंगे:

$ shopt -s extglob
$ cp !(*Music*) /target_directory

पूर्ण उपलब्ध ext समाप्त ग्लोब बिंग ऑपरेटर हैं (इससे अंश man bash):

यदि एक्सग्लोब शेल विकल्प को शॉप बिलिन का उपयोग करने में सक्षम किया जाता है, तो कई विस्तारित पैटर्न मिलान ऑपरेटरों को मान्यता दी जाती है। एक पैटर्न-सूची एक या एक से अलग पैटर्न की एक सूची है a | निम्नलिखित उप-पैटर्नों में से एक या अधिक का उपयोग करके समग्र पैटर्न बनाया जा सकता है:

  • ? (पैटर्न-सूची)
    दिए गए पैटर्न के शून्य या एक घटना से मेल खाती है
  • * (पैटर्न-सूची)
    दिए गए पैटर्न के शून्य या अधिक घटनाओं से मेल खाता है
  • + (पैटर्न-सूची)
    दिए गए पैटर्न की एक या अधिक घटनाओं से मेल खाता है
  • @ (पैटर्न-सूची)
    किसी दिए गए पैटर्न से मेल खाती है
  • ! (पैटर्न-सूची)
    दिए गए पैटर्न में से एक को छोड़कर किसी भी चीज से मेल खाता है

इसलिए, उदाहरण के लिए, यदि आप वर्तमान निर्देशिका में उन सभी फाइलों को सूचीबद्ध करना चाहते हैं जो फाइलें .cया नहीं हैं .h, तो आप ऐसा करेंगे:

$ ls -d !(*@(.c|.h))

बेशक, सामान्य शेल ग्लोबिंग कार्य करता है, इसलिए अंतिम उदाहरण के रूप में भी लिखा जा सकता है:

$ ls -d !(*.[ch])

1
-D का कारण क्या है?
बिग मैक्लेरजैग

2
मामले में से एक के लिए @Koveras .cया .hफ़ाइलें एक निर्देशिका है।
tzot

@DaveKennedy वर्तमान निर्देशिका में सब कुछ सूचीबद्ध करना है D, लेकिन उपनिर्देशिका की सामग्री नहीं जो निर्देशिका में निहित हो सकती है D
स्पर

23

बाश में नहीं (कि मुझे पता है), लेकिन:

cp `ls | grep -v Music` /target_directory

मुझे पता है कि यह वही नहीं है जो आप ढूंढ रहे थे, बल्कि यह आपके उदाहरण को हल करेगा।


डिफ़ॉल्ट ls प्रति पंक्ति में कई फाइलें डालेंगे, जो शायद सही परिणाम देने वाला नहीं है।
डैनियल बंगर्ट

10
केवल जब stdout एक टर्मिनल है। जब एक पाइपलाइन में उपयोग किया जाता है, तो एलएस एक फ़ाइलनाम प्रति पंक्ति प्रिंट करता है।
एडम रोसेनफील्ड

यदि टर्मिनल पर आउटपुट किया जाए तो ls केवल प्रति पंक्ति कई फाइलें रखता है। इसे स्वयं आज़माएँ - "ls। कम" में प्रति पंक्ति कई फाइलें कभी नहीं होंगी।
स्पूनमाइजर

3
यह रिक्त स्थान (या अन्य श्वेत स्पार्क वर्ण) वाले फ़ाइलनाम के लिए काम नहीं करेगा।
tzot 15

7

यदि आप निष्पादन कमांड का उपयोग करने की लागत से बचना चाहते हैं, तो मेरा मानना ​​है कि आप xargs के साथ बेहतर कर सकते हैं। मुझे लगता है कि निम्नलिखित एक अधिक कुशल विकल्प है

find foo -type f ! -name '*Music*' -exec cp {} bar \; # new proc for each exec



find . -maxdepth 1 -name '*Music*' -prune -o -print0 | xargs -0 -i cp {} dest/

6

बैश में, वैरिएबलshopt -s extglob का एक विकल्प है । यह वास्तव में बेहतर नहीं है, लेकिन मुझे याद रखना आसान है।GLOBIGNORE

एक उदाहरण जो मूल पोस्टर चाहता था वह हो सकता है:

GLOBIGNORE="*techno*"; cp *Music* /only_good_music/

जब किया, स्रोत निर्देशिका में unset GLOBIGNOREसक्षम होने के लिए rm *techno*


5

तुम भी एक बहुत ही सरल उपयोग कर सकते हैं for लूप का :

for f in `find . -not -name "*Music*"`
do
    cp $f /target/dir
done

1
यह एक पुनरावर्ती खोज करता है, जो ओपी चाहता है की तुलना में अलग व्यवहार है।
एडम रोसेनफील्ड

1
-maxdepth 1गैर-पुनरावर्ती के लिए उपयोग करें ?
एव्टोमेटन

मुझे शेल विकल्पों को सक्षम / अक्षम किए बिना यह सबसे साफ समाधान लगता है। इस पोस्ट में ओम्पी द्वारा आवश्यक परिणाम के लिए -maxdepth विकल्प की सिफारिश की जाएगी, लेकिन यह सब इस बात पर निर्भर करता है कि आप क्या हासिल करना चाहते हैं।
डेविड लैपॉइंट

findयदि किसी भी nontrivial फ़ाइल नामों को ढूंढता है तो बैकटिक्स का उपयोग अप्रिय तरीकों से टूट जाएगा।
ट्रिपल

5

मेरी व्यक्तिगत प्राथमिकता grep और जबकि कमांड का उपयोग करना है। यह एक शक्तिशाली अभी तक पठनीय स्क्रिप्ट लिखने के लिए अनुमति देता है यह सुनिश्चित करता है कि आप अंत में वही करना चाहते हैं जो आप चाहते हैं। इसके अलावा एक गूंज कमांड का उपयोग करके आप वास्तविक ऑपरेशन को अंजाम देने से पहले सूखा रन कर सकते हैं। उदाहरण के लिए:

ls | grep -v "Music" | while read filename
do
echo $filename
done

उन फ़ाइलों का प्रिंट आउट लेगा जिन्हें आप कॉपी करेंगे। यदि सूची सही है, तो अगला चरण कॉपी कमांड के साथ इको कमांड को बस इस प्रकार बदलना है:

ls | grep -v "Music" | while read filename
do
cp "$filename" /target_directory
done

1
यह तब तक काम करेगा जब तक कि आपके फ़ाइल नामों में कोई टैब, नया अंक, एक पंक्ति में एक से अधिक स्थान, या कोई बैकस्लैश न हो। जबकि वे रोग संबंधी मामले हैं, संभावना के बारे में पता होना अच्छा है। में bashआप का उपयोग कर सकते हैं while IFS='' read -r filename, लेकिन तब newlines अभी भी एक समस्या है। सामान्य रूप lsसे फ़ाइलों को एन्यूमरेट करने के लिए उपयोग नहीं करना सबसे अच्छा है ; जैसे उपकरण findबहुत बेहतर अनुकूल हैं।
थ्रेडवर्ड

बिना किसी अतिरिक्त उपकरण के:for file in *; do case ${file} in (*Music*) ;; (*) cp "${file}" /target_directory ; echo ;; esac; done
थेडवर्ड

mywiki.wooledge.org/ParsingLs कई अतिरिक्त कारणों की सूची देता है कि आपको इससे क्यों बचना चाहिए।
ट्रिपल

5

एक चाल मैं यहाँ पर अभी तक नहीं देखा है कि उपयोग नहीं करता है extglob, findया grepसेट के रूप में दो फ़ाइल सूचियों और इलाज के लिए है "diff" उन्हें प्रयोग comm:

comm -23 <(ls) <(ls *Music*)

commपर अधिक बेहतर है diffक्योंकि इसमें अतिरिक्त क्रॉफ्ट नहीं है।

यह रिटर्न सेट 1 के सभी तत्वों, ls, कि कर रहे हैं नहीं सेट 2 में भी ls *Music*। इसके लिए दोनों सेटों को ठीक से काम करने के लिए क्रमबद्ध क्रम में होना आवश्यक है। lsऔर ग्लोब विस्तार के लिए कोई समस्या नहीं है , लेकिन अगर आप कुछ का उपयोग कर रहे हैं find, तो सुनिश्चित करें sort

comm -23 <(find . | sort) <(find . | grep -i '.jpg' | sort)

संभावित रूप से उपयोगी।


1
बहिष्करण के लाभों में से एक को पहले स्थान पर निर्देशिका को पीछे नहीं करना है। यह समाधान उप-निर्देशिकाओं के दो ट्रैवर्सल्स करता है - एक अपवर्जन के साथ और एक बिना।
मार्क स्टोसबर्ग

बहुत अच्छी बात है, @MarkStosberg। हालाँकि, इस तकनीक का एक लाभ यह है कि आप वास्तविक फ़ाइल से बहिष्करण पढ़ सकते हैं, जैसेcomm -23 <(ls) exclude_these.list
जेम्स एम। लेट

3

इसके लिए एक समाधान खोजा जा सकता है।

$ mkdir foo bar
$ touch foo/a.txt foo/Music.txt
$ find foo -type f ! -name '*Music*' -exec cp {} bar \;
$ ls bar
a.txt

ढूँढें के पास कुछ विकल्प हैं, आप जो कुछ भी शामिल करते हैं और बाहर करते हैं, उस पर बहुत विशिष्ट प्राप्त कर सकते हैं।

संपादित करें: टिप्पणियों में एडम ने कहा कि यह पुनरावर्ती है। इसके विकल्प को खोजने के लिए माइंडपीथ और मैक्सडेपथ उपयोगी हो सकते हैं।


यह एक पुनरावर्ती प्रतिलिपि बनाता है, जो अलग व्यवहार है। यह प्रत्येक फ़ाइल के लिए एक नई प्रक्रिया भी पैदा करता है, जो बड़ी संख्या में फ़ाइलों के लिए बहुत अक्षम हो सकती है।
एडम रोसेनफील्ड

एक प्रक्रिया को पैदा करने की लागत सभी IO की तुलना में लगभग शून्य है जो प्रत्येक फ़ाइल को कॉपी करती है। तो मैं कहूंगा कि यह सामयिक उपयोग के लिए पर्याप्त है।
21

स्पॉनिंग प्रक्रिया के लिए कुछ वर्कअराउंड: stackoverflow.com/questions/186099/…
विन्को वर्सलोविच

पुनरावृत्ति से बचने के लिए "-Maxdepth 1" का उपयोग करें।
ईजगोटल

शेल वाइल्ड कार्ड विस्तार के अनुरूप पाने के लिए बैकटिक्स का उपयोग करें: cp find -maxdepth 1 -not -name '*Music*'/ target_directory
ejgottl

2

निम्नलिखित कार्य सभी को सूचीबद्ध करता है *.txt वर्तमान डीआईआर में फाइलों को , सिवाय उनके जो एक संख्या से शुरू होते हैं।

इस में काम करता है bash, dash, zshऔर अन्य सभी POSIX संगत गोले।

for FILE in /some/dir/*.txt; do    # for each *.txt file
    case "${FILE##*/}" in          #   if file basename...
        [0-9]*) continue ;;        #   starts with digit: skip
    esac
    ## otherwise, do stuff with $FILE here
done
  1. एक पंक्ति में पैटर्न /some/dir/*.txtउन forसभी फाइलों पर लूप को पुनरावृत्त करने का कारण होगा /some/dirजिनके नाम के साथ समाप्त होता है.txt

  2. लाइन टू में एक केस स्टेटमेंट का उपयोग अवांछित फ़ाइलों को हटाने के लिए किया जाता है। - ${FILE##*/}अभिव्यक्ति फ़ाइल नाम (यहां /some/dir/) से किसी भी प्रमुख dir नाम घटक को बंद कर देती है ताकि पेटेंट फ़ाइल के केवल आधार के खिलाफ मेल कर सकें। (यदि आप केवल प्रत्ययों के आधार पर फ़ाइल नाम का निराकरण कर रहे हैं, तो आप इसे छोटा कर सकते हैं$FILE इसके बजाय ।)

  3. पंक्ति तीन में, caseपैटर्न से मेल खाने वाली सभी फाइलें [0-9]*छोड़ दी जाएंगी ( continueकथन forलूप के अगले पुनरावृत्ति पर कूद जाता है )। - यदि आप चाहते हैं कि आप यहाँ कुछ और दिलचस्प कर सकें, जैसे कि सभी फ़ाइलों को छोड़ देना, जो एक अक्षर (a-z) के साथ शुरू नहीं होती है [!a-z]*, या आप कई प्रकार के फ़ाइल नाम को छोड़ने के लिए कई पैटर्न का उपयोग कर सकते हैं जैसे [0-9]*|*.bakकि दोनों .bakफ़ाइलों को छोड़ना , और फाइलें जो एक नंबर से शुरू नहीं होती हैं।


रवींद्र! एक बग था (मैं *.txtसिर्फ के बजाय के खिलाफ मिलान *)। अब तय हो गया।
zrajm

0

यह वास्तव में 'संगीत' को छोड़कर होगा

cp -a ^'Music' /target

यह और कि संगीत जैसी चीजों को छोड़कर? * या *? संगीत

cp -a ^\*?'complete' /target
cp -a ^'complete'?\* /target

cpMacOS पर मैन्युअल पृष्ठ एक है -aविकल्प है, लेकिन यह कुछ पूरी तरह से अलग करता है। कौन सा मंच इसका समर्थन करता है?
ट्रिपल
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.