शेल फ़ाइल नाम पैटर्न जो डॉट फ़ाइलों तक फैलता है, लेकिन `..` के लिए नहीं?


13

हाल ही में मुझे एक शेल पैटर्न के कारण थोड़ा हादसा हुआ जो अप्रत्याशित तरीके से विस्तारित हुआ। मैं /rootनिर्देशिका में डॉट फाइलों के एक समूह के मालिक को बदलना चाहता था , इसलिए मैंने किया

chown -R root .*

स्वाभाविक रूप से, जो .*विस्तारित ..था एक आपदा का एक सा था।

मैं में पता bashइस व्यवहार कुछ खोल विकल्प अदल-बदल करके बदला जा सकता है, लेकिन डिफ़ॉल्ट सेटिंग के साथ कोई पैटर्न है कि निर्देशिका में हर डॉट फाइल करने के लिए विस्तार होगा, लेकिन करने के लिए नहीं है .और ..?

जवाबों:


20

बैश, ksh और zsh में बेहतर समाधान हैं, लेकिन इस उत्तर में मैं एक POSIX शेल मानता हूं।

पैटर्न .[!.]*उन सभी फाइलों से मेल खाता है जो एक गैर-डॉट चरित्र के बाद एक डॉट से शुरू होती हैं। (ध्यान दें कि [^.]कुछ गोले द्वारा समर्थित है लेकिन सभी नहीं, वाइल्डकार्ड पैटर्न में वर्ण सेट पूरक के लिए पोर्टेबल वाक्य रचना है [!.]।) इसलिए यह शामिल नहीं .है और .., लेकिन यह भी फ़ाइलों को दो डॉट्स के साथ शुरू करते हैं। पैटर्न उन ..?*फ़ाइलों को संभालता है जो दो डॉट्स से शुरू होती हैं और बस नहीं हैं ..

chown -R root .[!.]* ..?*

यह सभी फ़ाइलों से मेल खाने वाला शास्त्रीय पैटर्न है:

* .[!.]* ..?*

इस दृष्टिकोण की एक सीमा यह है कि यदि पैटर्न में से कोई भी कुछ मेल नहीं खाता है, तो यह कमांड को पास कर दिया जाता है। एक स्क्रिप्ट में, जब आप एक डायरेक्टरी को छोड़कर सभी फाइलों को मैच करना चाहते हैं .और .., कई समाधान हैं, तो सभी बोझिल हैं:

  • का प्रयोग करें * .*सभी प्रविष्टियों की गणना करने में, और बाहर निकालने .और ..एक पाश में। एक या दोनों पैटर्न कुछ भी मेल नहीं खा सकते हैं, इसलिए लूप को प्रत्येक फ़ाइल के अस्तित्व की जांच करनी होगी। आपके पास अन्य मानदंडों पर फ़िल्टर करने का अवसर है; उदाहरण के लिए, -hयदि आप प्रतीकात्मक लिंक को लटकाना छोड़ना चाहते हैं तो परीक्षण को हटा दें ।

    for x in * .*; do
      case $x in .|..) continue;; esac
      [ -e "$x" ] || [ -h "$x" ] || continue
      somecommand "$x"
    done
  • एक अधिक जटिल संस्करण जहां कमांड केवल एक बार चलाया जाता है। ध्यान दें कि स्थितीय पैरामीटर क्लॉबर्ड हैं (POSIX गोले में सरणियाँ नहीं हैं); इसे एक अलग फ़ंक्शन में रखें यदि यह एक समस्या है।

    set --
    for x in * .[!.]* ..?*; do
      case $x in .|..) continue;; esac
      [ -e "$x" ] || [ -h "$x" ] || continue
      set -- "$@" "$x"
    done
    somecommand "$@"
  • * .[!.]* ..?*ट्राइपटिक का प्रयोग करें । फिर से, एक या अधिक पैटर्न कुछ भी मेल नहीं खा सकते हैं, इसलिए हमें मौजूदा फ़ाइलों (झूलने वाले प्रतीकात्मक लिंक सहित) की जांच करने की आवश्यकता है।

    for x in * .[!.]* ..?*; do
      [ -e "$x" ] || [ -h "$x" ] || continue
      somecommand "$x"
    done
  • * .[!.]* ..?*ट्राइपटिच का उपयोग करें , और प्रति पैटर्न एक बार कमांड चलाएं, लेकिन केवल अगर यह कुछ से मेल खाता है। यह केवल एक बार कमांड चलाता है। ध्यान दें कि स्थितीय पैरामीटर क्लॉबर्ड हैं (POSIX गोले में एरेज़ नहीं हैं), इसे एक अलग फ़ंक्शन में रखें यदि यह एक समस्या है।

    set -- *
    [ -e "$1" ] || [ -h "$1" ] || shift
    set -- .[!.]* "$@"
    [ -e "$1" ] || [ -h "$1" ] || shift
    set -- ..?* "$@"
    [ -e "$1" ] || [ -h "$1" ] || shift
    somecommand "$@"
  • का उपयोग करें find। जीएनयू या बीएसडी खोज के साथ, प्रत्यावर्तन परहेज विकल्पों के साथ आसान है -mindepthऔर -maxdepth। POSIX खोजने के साथ, यह थोड़ा मुश्किल है, लेकिन किया जा सकता है। इस फ़ॉर्म में आसानी से एक बार प्रति फ़ाइल के बजाय कमांड को चलाने की अनुमति देने का लाभ है (लेकिन इसकी गारंटी नहीं है: यदि परिणामी कमांड बहुत लंबी है, तो कमांड को कई बैचों में चलाया जाएगा)।

    find . -name . -o -exec somecommand {} + -o -type d -prune

6

यह काम करता है अगर सभी फ़ाइल नाम में कम से कम तीन अक्षर (डॉट सहित) हों:

chown -R root .??*

अधिक मजबूत समाधान के लिए, आप उपयोग कर सकते हैं find:

find . -maxdepth 1 -name '.*' -exec chown -R root {} \;
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.