दो या अधिक फ़ाइलों के साथ निर्देशिकाएँ


11

मैं वर्तमान निर्देशिका की एक उपनिर्देशिका ढूंढना चाहता हूं, जिसमें (जो कि उपनिर्देशिका है) में 2 या अधिक नियमित फाइलें हैं।

मुझे उन निर्देशिकाओं में दिलचस्पी नहीं है जिनमें 2 से कम फाइलें हैं, न ही ऐसी निर्देशिकाओं में जिनमें केवल उपनिर्देशिकाएँ हैं।

जवाबों:


12

यहाँ GNU पर आधारित findऔर पूरी तरह से अलग दृष्टिकोण है uniq। यह एक शेल कमांड को निष्पादित करने के आधार पर उत्तर की तुलना में बहुत तेज और बहुत सीपीयू-अनुकूल है जो प्रत्येक निर्देशिका के लिए फ़ाइलों की गणना करता है।

find . -type f -printf '%h\n' | sort | uniq -d

findआदेश पदानुक्रम में सभी फाइलों की सूची प्रिंट और uniqकेवल निर्देशिका कि दो बार कम से कम दिखाई देते हैं प्रदर्शित करता है।


2
आपको आउटपुट को पार्स नहीं करना चाहिए find। इस मामले में, क्योंकि जीएनयू findउन निर्देशिकाओं के नामों को संकलित करेगा जिनके पास वर्तमान लोकेल में मुद्रण योग्य नहीं हैं (जैसे सी लोकेल में "ä")। यह भी देखें unix.stackexchange.com/questions/321697/...
Kusalananda

4
@ कुसलानंद, तब नहीं जब आउटपुट टटी नहीं। यहां, एकमात्र समस्या न्यूलाइन वर्णों के साथ है, जिसे आप उपयोग करके ठीक कर सकते हैं-printf '%h\0' | sort -z | uniq -zd | xargs -r0 ...
स्टीफन चेज़लस

6
find . -type d \
    -exec sh -c 'c=0; for n in "$1"/*; do [ -f "$n" ] && [ ! -h "$n" ] && c=$(( c + 1 )); done; [ "$c" -ge 2 ]' sh {} ';' \
    -print

यह वर्तमान निर्देशिका में या उसके नीचे सभी नामों को खोजेगा और फिर उन सभी नामों को फ़िल्टर करेगा जो निर्देशिकाओं के नाम नहीं हैं।

शेष निर्देशिका नाम इस लघु लिपि को दिए जाएंगे:

c=0
for n in "$1"/*; do
    [ -f "$n" ] && [ ! -h "$n" ] && c=$(( c + 1 ))
done

[ "$c" -ge 2 ]

यह स्क्रिप्ट पहले कमांड लाइन तर्क (से find) के रूप में दी गई निर्देशिका में नियमित फाइलों (प्रतीकात्मक लिंक्स को छोड़ना) की संख्या की गणना करेगी । स्क्रिप्ट में अंतिम कमांड यह देखने के लिए एक परीक्षण है कि क्या गिनती 2 या अधिक थी। इस परीक्षण का परिणाम स्क्रिप्ट का रिटर्न मान (निकास स्थिति) है।

यदि परीक्षण सफल हुआ, तो निर्देशिका के लिए मार्ग का प्रिंट आउट किया -printजाएगा find

छिपी हुई फ़ाइलों पर विचार करने के लिए (फाइलें जिनके नाम डॉट से शुरू होते हैं), sh -cस्क्रिप्ट को कहने से बदल दें

for n in "$1"/*; do

सेवा

for n in "$1"/* "$1"/.*; do

परिक्षण:

$ tree
.
`-- test
    |-- a
    |-- dir1
    |   |-- a
    |   |-- b
    |   `-- c
    `-- dir2
        |-- dira
        |-- dirb
        |   |-- file-1
        |   `-- file-2
        `-- dirc

6 directories, 6 files

$ find . -type d -exec sh -c 'c=0; for n in "$1"/*; do [ -f "$n" ] && [ ! -h "$n" ] && c=$(( c + 1 )); done; [ "$c" -ge 2 ]' sh {} ';' -print
./test/dir1
./test/dir2/dirb

आपका समाधान एक डॉट के साथ शुरू होने वाले नाम के साथ फाइलों की गिनती नहीं करता है। निर्देशिकाओं के साथ त्रुटि संदेशों से बचने के लिए आपको c = 0 को इनिशियलाइज़ करना चाहिए जिसमें कोई फ़ाइल न हो।
xhienne

@xhienne मैं छिपी हुई फ़ाइलों पर विचार करता था और इसके बारे में एक नोट जोड़ूंगा। यदि कोई [ "" -ge 2 ]मान्य परीक्षण है, तो निर्देशिका में कोई नियमित फ़ाइलें नहीं हैं, तो कोई त्रुटि नहीं है।
Kusalananda

निश्चित नहीं है कि आप "वैध" कैसे परिभाषित करते हैं। POSIX को पूर्णांक मान होने के लिए arg1 की आवश्यकता होती है। dash, bash --posixऔर testसभी एक त्रुटि संदेश प्रदर्शित करते हैं और 2 के साथ बाहर निकलते हैं (यानी "एक त्रुटि हुई")
xhienne

@xhienne आह, मैं एक ऐसे सिस्टम पर परीक्षण कर रहा था जो मैस के kshरूप में चल रहा था sh। तुरंत संशोधन करेंगे। मुझ पर प्रहार करने के लिए धन्यवाद! :-)
Kusalananda

इसके अलावा, [ -f ... ]dereferences प्रतीकात्मक लिंक। आपको उन्हें समाप्त करने के लिए एक परीक्षण जोड़ना चाहिए क्योंकि सवाल निर्दिष्ट करता है कि केवल नियमित फ़ाइलों को गिना जाना चाहिए।
xhienne

6

की मदद से गाइल्स के जवाब पर SU और उसके रिवर्स और कुछ संशोधन, यहाँ आप क्या जरूरत है।

find . -type d -exec sh -c 'set -- "$1"/*;X=0; 
    for args; do [ -f "$args" ] && X=$((X+1)) ;done; [ "$X" -gt 1 ] ' _ {} \; -print

निर्देशिका पेड़।

.
├── test
│   ├── dir1
│   │   ├── a
│   │   ├── b
│   │   └── c
│   ├── dir2
│   │   ├── dira
│   │   │   └── a file\012with\012multiple\012line
│   │   ├── dirb
│   │   │   ├── file-1
│   │   │   └── file-2
│   │   └── dirc
│   ├── diraa
│   ├── dirbb
│   ├── dircc
│   └── x
│   └── x1
│   └── x2
└── test2
    ├── dir3
    └── dir4

परिणाम:

./test
./test/dir1
./test/dir2/dirb

मेरे पास पहले भी यही था, लेकिन आपको कई उपनिर्देशिकाओं और फ़ाइलों वाली निर्देशिकाओं के साथ समस्या होगी । यह भी केवल उपनिर्देशिका युक्त निर्देशिकाओं का निराकरण नहीं करता है।
Kusalananda

यह वास्तव में इसे हल नहीं करता है। यह दोनों पाता है testऔर dir2अपने परीक्षण सेटअप में निर्देशिका (मेरा उत्तर देखें)।
Kusalananda

आपके उदाहरण के लिए काम करता है, लेकिन जोड़ने test/x1और test/x2फ़ाइलों के रूप में रूप में अच्छी तरह ... $1और $2के लिए निर्देशिका हो जाएगा test, और निर्देशिका छूट जाएँगी।
Kusalananda

@ कुसलानंद आपके द्वारा दिए गए जवाब के अलावा मुझे कोई रास्ता नहीं मिला, मैंने अपनी आज्ञा के कुछ हिस्से को बदलने की कोशिश की, ताकि आपकी बिल्कुल भी नकल न हो (मैंने आपकी तरह छिपी हुई फाइलों को बाहर नहीं किया), मेरी माफी।
α atsнιη

1
जो भी कोई चिंता नहीं :-)
Kusalananda

3

एक और find+ wcदृष्टिकोण:

find path/currdir -maxdepth 1 -type d ! -empty ! -path "path/currdir" \
-exec sh -c 'count=$(find "$1" -maxdepth 1 -type f | wc -l); [ $count -ge 2 ]' _ {} \; -print

  • path/currdir - अपने वर्तमान निर्देशिका के लिए पथ

  • -maxdepth 1- केवल प्रत्यक्ष बाल सबफ़ोल्डर्स पर विचार करें

  • ! -empty - खाली सबफोल्डर्स को नजरअंदाज करें

  • ! -path "path/currdir" - वर्तमान निर्देशिका पथ पर ध्यान न दें

  • count=$(find "$1" -maxdepth 1 -type f | wc -l)- countप्रत्येक पाया सबफ़ोल्डर के लिए फ़ाइलों की संख्या के साथ सौंपा गया है

  • [ $count -ge 2 ] ... -print - प्रिंट सबफ़ोल्डर नाम / पथ जिसमें 2 या अधिक नियमित फाइलें हों

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.