Emacs lisp: `directory-files`




elisp interactive (2)

फ़ंक्शन directory-files रिटर्न करती हैं और .. प्रविष्टियां भी हैं एक अर्थ में यह सच है, कि केवल इस तरह से फ़ंक्शन सभी मौजूदा प्रविष्टियां देता है, मुझे अभी तक इन्हें शामिल करने के लिए एक उपयोग देखना नहीं है। दूसरी ओर, हर बार जब मैं directory-files इस्तेमाल directory-files हूं तो मैं कुछ भी लिखता हूं

(unless (string-match-p "^\\.\\.?$" ... 

या बेहतर दक्षता के लिए

(unless (or (string= "." entry)
            (string= ".." entry))
   ..)

विशेष रूप से इंटरैक्टिव उपयोग ( M-: में अतिरिक्त कोड अवांछनीय है।

क्या कोई पूर्वनिर्धारित कार्य है जो किसी निर्देशिका के केवल वास्तविक उप-भाग को कुशलतापूर्वक देता है?


यदि आप f.el , एक सुविधाजनक फ़ाइल और निर्देशिका हेरफेर लाइब्रेरी का उपयोग करते हैं, तो आपको केवल फ़ंक्शन f-entries आवश्यकता होती है।

हालांकि, अगर आप किसी कारण के लिए इस लाइब्रेरी का उपयोग नहीं करना चाहते हैं और आप गैर-पोर्टेबल * निकस समाधान के लिए ठीक हैं, तो आप ls कमांड का उपयोग कर सकते हैं।

(defun my-directory-files (d)
  (let* ((path (file-name-as-directory (expand-file-name d)))
         (command (concat "ls -A1d " path "*")))
    (split-string (shell-command-to-string command) "\n" t)))

उपरोक्त कोड पर्याप्त है, लेकिन स्पष्टीकरण के लिए आगे पढ़ें।

डॉट्स से छुटकारा पाएं

man ls अनुसार man ls :

   -A, --almost-all
          do not list implied . and ..

split-string जो व्हाटस्पेस द्वारा split-string को विभाजित करती है, हम ls आउटपुट को पार्स कर सकते हैं:

(split-string (shell-command-to-string "ls -A"))

फ़ाइल नामों में रिक्त स्थान

समस्या यह है कि कुछ फाइलनामों में रिक्त स्थान हो सकते हैं split-string डिफ़ॉल्ट विभाजन द्वारा regex द्वारा split-string-default-separators विभेदकों में split-string-default-separators करती है, जो "[ \f\t\n\r\v]+"

   -1     list one file per line

-1 को एकमात्र विभाजक के रूप में "\n" पारित करने के लिए, नई लाइन द्वारा फ़ाइलें सीमांकित करने की अनुमति देता है। आप इसे किसी फ़ंक्शन में लपेट सकते हैं और इसे अनैतिक निर्देशिका के साथ उपयोग कर सकते हैं।

(split-string (shell-command-to-string "ls -A1") "\n")

प्रत्यावर्तन

लेकिन क्या होगा अगर आप लगातार उपनिर्देशों में डुबकी करना चाहते हैं, भविष्य में उपयोग के लिए फाइल लौट रहे हैं? यदि आप केवल निर्देशिका और मुद्दा ls बदलते हैं, तो आपको पथ के बिना फ़ाइल नाम मिलेगा, इसलिए एएमएसीएस को यह नहीं पता होगा कि यह फाइल कहाँ स्थित है। एक समाधान है कि ls हमेशा पूर्ण पथ को वापस लाता है। man ls अनुसार man ls :

   -d, --directory
          list directory entries instead of contents, and do not dereference symbolic links

यदि आप वाइल्डकार्ड और -d विकल्प के साथ निर्देशिका में पूर्ण पथ पास करते हैं, तो आपको लिनक्स में अपने संपूर्ण पथ के साथ फाइल कैसे सूचीबद्ध कर सकते हैं , इसके अनुसार आपको तत्काल फ़ाइलों और उपनिर्देशिका के पूर्ण पथ की सूची मिल जाएगी । । पथ निर्माण पर स्पष्टीकरण के लिए , एलीस्प में, स्लैश के साथ पथ स्ट्रिंग कैसे ठीक से डाली जाए? ।

(let ((path (file-name-as-directory (expand-file-name d))))
  (split-srting (shell-command-to-string (concat "ls -A1d " path "*")) "\n"))

नल स्ट्रिंग रद्द करना

यूनिक्स कमांड को आउटपुट के लिए पिछली श्वेत स्थान को जोड़ना है, ताकि प्रॉम्प्ट नई लाइन पर हो। इसके बदले अन्यथा:

user@host$ ls
somefile.txt
user@host$

वहाँ होगा:

user@host$ ls
somefile.txtuser@host$

जब आप कस्टम विभाजक को split-string , तो यह इस नई लाइन को अपनी तरफ के रूप में मानता है। सामान्य तौर पर, यह सीएसवी फाइलों को सही तरीके से पार्स करने की अनुमति देता है, जहां एक खाली रेखा वैध डेटा हो सकती है। लेकिन ls साथ हम एक रिक्त-स्ट्रिंग के साथ समाप्त होते हैं, जिसे t को पारित split-string तीसरे पैरामीटर के रूप में पास करके छोड़ा जाना चाहिए।


आप मूल फ़ंक्शन कॉल के भाग के रूप में ऐसा कर सकते हैं।

(directory-files DIRECTORY &optional FULL MATCH NOSORT)

If MATCH is non-nil, mention only file names that match the regexp MATCH.

इसलिए:

(directory-files (expand-file-name "~/") nil "^\\([^.]\\|\\.[^.]\\|\\.\\..\\)")

या:

(defun my-directory-files (directory &optional full nosort)
  "Like `directory-files' with MATCH hard-coded to exclude \".\" and \"..\"."
  (directory-files directory full "^\\([^.]\\|\\.[^.]\\|\\.\\..\\)" nosort))

यद्यपि अपने स्वयं के दृष्टिकोण के समान कुछ और अधिक कुशल आवरण के लिए हो सकता है, वास्तव में

(defun my-directory-files (directory &optional full match nosort)
  "Like `directory-files', but excluding \".\" and \"..\"."
  (delete "." (delete ".." (directory-files directory full match nosort))))

हालांकि यह सूची दो बार प्रसंस्करण कर रही है, और हमें पता है कि हम उन प्रत्येक नामों का केवल एक उदाहरण है जो हम बाहर करना चाहते हैं (और एक उचित मौका है जो वे पहले दिखाई देंगे), तो ऐसा कुछ और अच्छा हो सकता है यदि आप अपेक्षाकृत बड़े आधार पर डायरेक्टरी से निपटने की उम्मीद:

(defun my-directory-files (directory &optional full match nosort)
  "Like `directory-files', but excluding \".\" and \"..\"."
  (let* ((files (cons nil (directory-files directory full match nosort)))
         (parent files)
         (current (cdr files))
         (exclude (list "." ".."))
         (file nil))
    (while (and current exclude)
      (setq file (car current))
      (if (not (member file exclude))
          (setq parent current)
        (setcdr parent (cdr current))
        (setq exclude (delete file exclude)))
      (setq current (cdr current)))
    (cdr files)))




interactive