POSIX को विशिष्ट गहराई तक सीमित करें?


15

मैंने हाल ही में देखा कि POSIX विनिर्देशोंfind में -maxdepthप्राथमिक शामिल नहीं है ।

इसके साथ अपरिचित लोगों के लिए, -maxdepthप्राथमिक का उद्देश्य यह प्रतिबंधित करना है कि कितने स्तर गहरे findउतरेंगे। संसाधित होने वाली केवल कमांड लाइन तर्कों -maxdepth 0में परिणाम ; केवल कमांड लाइन आर्ग्युमेंट्स आदि के भीतर ही परिणाम को सीधे हैंडल करेगा।-maxdepth 1

मैं -maxdepthकेवल POSIX- निर्दिष्ट विकल्पों और उपकरणों का उपयोग करके गैर-POSIX प्राथमिक के समान व्यवहार कैसे प्राप्त कर सकता हूं ?

(ध्यान दें: बेशक मैं पहले ऑपरेंड के रूप में -maxdepth 0उपयोग करके इसके बराबर प्राप्त कर सकता हूं -prune, लेकिन यह अन्य गहराई तक नहीं है।)


@StevenPenny, FreeBSD की -depth -2, -depth 1... दृष्टिकोण को GNU की तुलना में बेहतर देखा जा सकता है -maxdepth/-mindepth
Stéphane Chazelas

@ स्टीफनचेज़लस या तो रास्ता - पॉसिक्स में एक या दूसरे को ढूंढना चाहिए; इसके अलावा यह अपंग है
स्टीवन पेन्नी

1
कम से कम -maxdepth/ के लिए -mindepth, उचित विकल्प हैं (ध्यान दें कि -pathहाल ही में POSIX के अतिरिक्त है)। -timexyया -mtime -3m(या -mmin -3) के लिए विकल्प बहुत अधिक बोझिल हैं। कुछ की तरह -execdir/ -deleteकोई विश्वसनीय विकल्प नहीं है।
स्टीफन चेज़लस

2
@StevenPenny, यह जोड़ने के लिए अनुरोध करने के लिए austingroupbugs.net पर टिकट लॉग इन करने के लिए स्वतंत्र महसूस करें । मैंने देखा है कि एक मजबूत औचित्य होने पर प्रायोजक की आवश्यकता के बिना चीजों को जोड़ा जाता है। कार्रवाई का एक बेहतर तरीका यह होगा कि कई कार्यान्वयन इसे पहले जोड़ दें ताकि POSIX को केवल उस मौजूदा को निर्दिष्ट करना होगा जो आम तौर पर कम विवादास्पद है।
स्टीफन चेजेलस

@ मेरे मामले में स्टीफनचेज़लस ने सीधे फाइलों के नामकरण को समाप्त कर दिया, लेकिन धन्यवाद; अगर यह फिर से आता है तो मैं टिकट दाखिल कर सकता हूं
स्टीवन पेनी

जवाबों:


7

आप -pathकिसी दिए गए गहराई और prune मैच के लिए उपयोग कर सकते हैं । उदाहरण के लिए

find . -path '*/*/*' -prune -o -type d -print

1 अधिकतम होगा, जैसा कि *मैचों ., */*मैचों ./dir1, और */*/*मैचों के बीच ./dir1/dir2होता है , जो छंट जाता है। यदि आप एक निरपेक्ष आरंभिक निर्देशिका का उपयोग करते हैं तो आपको एक अग्रणी /को -pathभी जोड़ना होगा ।


हम्म, मुश्किल। क्या आप /*पैटर्न के अंत से सिर्फ एक परत नहीं निकाल सकते, -oऑपरेटर को निकाल सकते हैं , और एक ही परिणाम प्राप्त कर सकते हैं?
वाइल्डकार्ड

नहीं, क्योंकि साथ ही साथ *मेल खाता है /, इसलिए डायर a/b/c/d/eफिट होगा -path */*, दुख की बात है।
मयूह

लेकिन a/b/c/d/eकभी नहीं पहुंचेगा , क्योंकि -pruneलागू किया जाएगा a/b....
वाइल्डकार्ड

1
क्षमा करें, मैंने इसे गलत समझा -pruneऔर -oहटा दिया गया। यदि आप -pruneयह समस्या रखते हैं कि */*अधिकतमड्रेड के ऊपर एक स्तर पर कुछ भी मेल नहीं खाएगा, जैसे एकल निर्देशिका a
meuh

11

@ meuh का दृष्टिकोण अक्षम है क्योंकि उनका -maxdepth 1दृष्टिकोण अभी भी find1 स्तर पर निर्देशिकाओं की सामग्री को पढ़ने देता है ताकि बाद में उन्हें अनदेखा कर सकें। यह कुछ findकार्यान्वयन (GNU सहित find) के साथ ठीक से काम नहीं करेगा यदि कुछ निर्देशिका नामों में बाइट्स के अनुक्रम होते हैं जो उपयोगकर्ता के स्थान में मान्य वर्ण नहीं बनाते हैं (जैसे किसी भिन्न वर्ण एन्कोडिंग में फ़ाइल नाम के लिए)।

find . \( -name . -o -prune \) -extra-conditions-and-actions

GNU's -maxdepth 1(या FreeBSD -depth -2) को लागू करने के लिए अधिक विहित तरीका है ।

आम तौर पर हालांकि, यह -depth 1आप चाहते हैं ( -mindepth 1 -maxdepth 1) के रूप में आप पर विचार नहीं करना चाहते .(गहराई 0), और फिर यह और भी सरल है:

find . ! -name . -prune -extra-conditions-and-actions

के लिए -maxdepth 2, वह बन जाता है:

find . \( ! -path './*/*' -o -prune \) -extra-conditions-and-actions

और यह वह जगह है जहाँ आप अमान्य वर्ण समस्याओं में चलते हैं।

उदाहरण के लिए, यदि आपके पास एक निर्देशिका है, Stéphaneलेकिन वह éiso8859-1 (उर्फ लैटिन 1) चारसेट (0xe9 बाइट) में एन्कोडेड है, जैसा कि पश्चिमी यूरोप और अमेरिका में 2000 के दशक के मध्य तक सबसे आम था, तो 0xe9 बाइट कोई नहीं है। UTF-8 में मान्य वर्ण। तो, UTF-8 स्थानों में, *वाइल्डकार्ड (कुछ के साथ findकार्यान्वयन) से मेल नहीं खाएगी Stéphaneके रूप में *0 या उससे अधिक है वर्ण और 0xe9 एक चरित्र नहीं है।

$ locale charmap
UTF-8
$ find . -maxdepth 2
.
./St?phane
./St?phane/Chazelas
./Stéphane
./Stéphane/Chazelas
./John
./John/Smith
$ find . \( ! -path './*/*' -o -prune \)
.
./St?phane
./St?phane/Chazelas
./St?phane/Chazelas/age
./St?phane/Chazelas/gender
./St?phane/Chazelas/address
./Stéphane
./Stéphane/Chazelas
./John
./John/Smith

मेरा find(जब आउटपुट एक टर्मिनल पर जाता है) उस 0xe9 बाइट को ?ऊपर की तरह दिखाता है । आप देख सकते हैं कि डी St<0xe9>phane/Chazelasनहीं था prune

आप इसके द्वारा काम कर सकते हैं:

LC_ALL=C find . \( ! -path './*/*' -o -prune \) -extra-conditions-and-actions

लेकिन ध्यान दें कि यह findऔर इसके द्वारा चलाए जाने वाले किसी भी एप्लिकेशन की सभी स्थानीय सेटिंग्स को प्रभावित करता है (जैसे कि -execविधेय के माध्यम से )।

$ LC_ALL=C find . \( ! -path './*/*' -o -prune \)
.
./St?phane
./St?phane/Chazelas
./St??phane
./St??phane/Chazelas
./John
./John/Smith

अब, मुझे वास्तव में एक -maxdepth 2नोट मिल गया है कि कैसे दूसरे स्टीफन में é को ठीक से UTF-8 में एनकोड किया गया है, जो ??कि यूटीएफ -8 एन्कोडिंग के 0xc3 0xa9 बाइट्स (सी लोकेल में दो व्यक्तिगत अपरिभाषित पात्रों के रूप में) के रूप में प्रदर्शित होता है। सी लोकेल में प्रिंट करने योग्य अक्षर नहीं।

और अगर मैंने एक जोड़ -name '????????'दिया होता, तो मुझे गलत स्टीफन मिल जाता (एक iso8859-1 में एन्कोडेड)।

के बजाय मनमाने रास्तों पर लागू करने के लिए ., आप यह करेंगे:

find some/dir/. ! -name . -prune ...

के लिए -mindepth 1 -maxdepth 1या:

find some/dir/. \( ! -path '*/./*/*' -o -prune \) ...

के लिए -maxdepth 2

मैं अभी भी एक:

(cd -P -- "$dir" && find . ...)

पहला इसलिए कि इससे रास्ते बहुत छोटे हो जाते हैं, जिसके कारण बहुत लंबा रास्ता तय करना संभव हो जाता है या बहुत लंबी समस्याएँ आ जाती हैं लेकिन इस तथ्य के इर्द-गिर्द काम करना पड़ता है कि findवे मनमाने तरीके से तर्क का समर्थन नहीं कर सकते हैं ( -fफ्रीबीएसडी को छोड़कर find) क्योंकि यह चोक हो जाएगा $dirजैसे मान !या -print...


-oनिषेध के साथ संयोजन में एक आम चाल के दो स्वतंत्र सेट चलाने के लिए है -condition/ -actionमें find

यदि आप -action1फ़ाइल मीटिंग पर -condition1और स्वतंत्र रूप -action2से फ़ाइलों की मीटिंग पर चलना चाहते हैं -condition2, तो आप ऐसा नहीं कर सकते:

find . -condition1 -action1 -condition2 -action2

जैसा -action2कि दोनों शर्तों को पूरा करने वाली फ़ाइलों के लिए ही चलाया जाएगा ।

और न ही:

find . -contition1 -action1 -o -condition2 -action2

के रूप में दोनों शर्तों को -action2पूरा करने वाली फ़ाइलों के लिए नहीं चलाया जाएगा ।

find . \( ! -condition1 -o -action1 \) -condition2 -action2

के रूप में काम करता है हर फ़ाइल के \( ! -condition1 -o -action1 \)लिए सच का समाधान होगा । यह मानता -action1है कि एक क्रिया (जैसे ) -prune, -exec ... {} +जो हमेशा सच होती है । जैसे कार्यों के लिए -exec ... \;है कि वापस आ सकते हैं झूठी , आप एक और जोड़ सकते हैं -o -somethingजहां -somethingहानिरहित है लेकिन रिटर्न सच की तरह -trueजीएनयू में findया -links +0या -name '*'(हालांकि टिप्पणी ऊपर अमान्य वर्ण के बारे में मुद्दा)।


1
किसी दिन मैं चीनी फाइलों के एक समूह में चला जाऊंगा और मुझे बहुत खुशी होगी कि मैंने स्थानीय और मान्य पात्रों के बारे में आपके कई उत्तर पढ़े हैं। :)
वाइल्डकार्ड

2
@Wildcard, आप (और यहां तक ​​कि एक चीनी व्यक्ति) ब्रिटिश, फ्रेंच के साथ समस्या में चलने की अधिक संभावना है ... चीनी फ़ाइल नाम की तुलना में चीनी फ़ाइलनामों की तुलना में फ़ाइल नाम अधिक बार वर्णानुक्रमिक स्क्रिप्ट के फ़ाइल नामों की तुलना में UTF-8 में एन्कोड किए जाते हैं यह आम तौर पर एकल-बाइट चारसेट द्वारा कवर किया जा सकता है जो अपेक्षाकृत हाल ही तक आदर्श था। चीनी चरित्र को कवर करने के लिए अन्य मल्टी-बाइट चारसेट हैं, लेकिन मुझे उम्मीद है कि चीनी लोग पहले की तुलना में यूटीएफ -8 में बदल जाएंगे क्योंकि पश्चिमी देशों की तुलना में उन चार्टों में बहुत सारे समस्याएँ हैं। एक उदाहरण के लिए संपादन भी देखें।
स्टीफन चेजलस

0

मैं एक ऐसे मुद्दे पर भाग गया जहाँ मुझे कई रास्तों (केवल के बजाय .) की खोज करते समय गहराई को सीमित करने का एक तरीका चाहिए था ।

उदाहरण के लिए:

$ find dir1 dir2 -name myfile -maxdepth 1

यह -regex का उपयोग करके मुझे एक वैकल्पिक दृष्टिकोण की ओर ले गया। जिस्ट है:

-regex '(<list of paths | delimited>)/<filename>'

तो, उपरोक्त होगा:

$ find dir1 dir2 -name myfile -regextype awk -regex '(dir1|dir2)/myfile' # GNU
$ find -E dir1 dir2 -name myfile -regex '(dir1|dir2)/myfile' # MacOS BSD

फ़ाइल नाम के बिना:

$ find dir1 dir2 -name myfile -maxdepth 1 # GNU

-regex '(<list of paths | delimited>)/<anything that's not a slash>$'

$ find dir1 dir2 -name myfile -regextype awk -regex '(dir1|dir2)/[^/]*$' # GNU
$ find -E dir1 dir2 -name myfile -regex '(dir1|dir2)/[^/]*$' # MacOS BSD

अंत में, -maxdepth 2रेगेक्स परिवर्तनों के लिए:'(dir1|dir2)/([^/]*/){0,1}[^/]*$'


1
यह सवाल एक मानक के लिए पूछता है (POSIX के रूप में) हालांकि समाधान। -maxdepthकई खोज पथों के साथ भी काम करेगा।
कुसलानंद
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.