मैं बैश में केवल निर्देशिकाओं के माध्यम से कैसे लूप कर सकता हूं?


249

मेरे पास कुछ निर्देशिकाओं और कुछ फ़ाइलों के साथ एक फ़ोल्डर है (कुछ छिपे हुए हैं, डॉट के साथ शुरुआत)।

for d in *; do
 echo $d
done

सभी फ़ाइलों के माध्यम से लूप होगा, लेकिन मैं केवल निर्देशिका के माध्यम से लूप करना चाहता हूं। मैं उसको कैसे करू?

जवाबों:


331

आप केवल निर्देशिका से मिलान करने के लिए अंत में एक स्लैश निर्दिष्ट कर सकते हैं:

for d in */ ; do
    echo "$d"
done

7
ध्यान दें कि इसमें निर्देशिकाओं के लिए सीमलिंक भी शामिल हैं।
स्टीफन चेजलस

1
तो आप सिमिलिंक को बाहर कैसे करेंगे?
rubo77

3
@ rubo77: आप परीक्षण कर सकते हैं [[ -L $d ]]कि क्या $ d एक प्रतीकात्मक लिंक है।
कोरोबा

1
@AsymLabs यह गलत है, set -Pकेवल उन कमांड्स को प्रभावित करता है जो निर्देशिका बदलते हैं। sprunge.us/TNac
क्रिस डाउन

4
@choroba: [[ -L "$f" ]]इस मामले में सहानुभूति को बाहर नहीं करेगा */, आपको ट्रेलिंग स्लैश को स्ट्रिप करना होगा ( ट्रायल स्लैश के साथ लिंक के लिए टेस्ट[[ -L "${f%/}" ]] देखें )
rubo77

78

आप इसके साथ परीक्षण कर सकते हैं -d:

for f in *; do
    if [ -d "$f" ]; then
        # $f is a directory
    fi
done

यह फ़ाइल परीक्षण ऑपरेटरों में से एक है


8
ध्यान दें कि इसमें निर्देशिकाओं के लिए सीमलिंक शामिल होंगे।
स्टीफन चेजेलस

21
if [[ -d "$f" && ! -L "$f" ]]सिम्बलिंक को बाहर करेगा
रूब77 7

खाली निर्देशिका पर टूट जाएगा। if [[ "$f" = "*" ]]; then continue; fi
9

30

उस चोराबा के समाधान से सावधान रहें, हालांकि सुरुचिपूर्ण, अप्रत्याशित व्यवहार को हटा सकता है यदि कोई निर्देशिका वर्तमान निर्देशिका के भीतर उपलब्ध नहीं है। इस स्थिति में, forलूप स्किप करने के बजाय , बैश लूप को ठीक उसी समय चलाएगा, जब dवह बराबर होता है */:

#!/usr/bin/env bash

for d in */; do
    # Will print */ if no directories are available
    echo $d
done

मैं इस मामले से बचाव के लिए निम्नलिखित का उपयोग करने की सलाह देता हूं:

#!/usr/bin/env bash

for f in *; do
    if [ -d ${f} ]; then
        # Will not run if no directories are available
        echo $f
    fi
done

यह कोड वर्तमान निर्देशिका में सभी फ़ाइलों के माध्यम से लूप करेगा, यदि fकोई निर्देशिका है, तो यह जांचें कि क्या fस्थिति सही है या नहीं। यदि fसमान है */, echo $fतो निष्पादित नहीं करेगा।


3
बहुत आसान है shopt -s nullglob
कोरबा

21

यदि आपको केवल निर्देशिकाओं के उपयोग से अधिक विशिष्ट फ़ाइलों का चयन करने की आवश्यकता है, तो findइसे पास करें while read:

shopt -s dotglob
find * -prune -type d | while IFS= read -r d; do 
    echo "$d"
done

shopt -u dotglobछिपी निर्देशिका (या setopt dotglob/ unsetopt dotglobzsh में) को बाहर करने के लिए उपयोग करें ।

IFS=$IFSउदाहरण के लिए, इनमें से किसी एक को विभाजित करने वाले फ़ाइल नाम से बचने के लिए:'a b'

देख AsymLabs का जवाब और अधिक के लिए नीचे दिए गए findविकल्पों में


संपादित करें:
यदि आपको लूप के भीतर से बाहर निकलने का मूल्य बनाने की आवश्यकता होती है, तो आप इस ट्रिक द्वारा अतिरिक्त उपधारा को दरकिनार कर सकते हैं:

while IFS= read -r d; do 
    if [ "$d" == "something" ]; then exit 1; fi
done < <(find * -prune -type d)

2
मुझे यह समाधान मिला: stackoverflow.com/a/8489394/1069083
rubo77

11

आप इसके लिए शुद्ध बैश का उपयोग कर सकते हैं, लेकिन इसका उपयोग करना बेहतर है:

find . -maxdepth 1 -type d -exec echo {} \;

(अतिरिक्त रूप से छिपे निर्देशिकाओं को शामिल करें)


8
ध्यान दें कि इसमें निर्देशिकाओं के प्रति सहानुभूति शामिल नहीं है। आप छिपी निर्देशिकाओं को शामिल करने के shopt -s dotglobलिए उपयोग कर सकते हैं bash। तुम्हारा भी शामिल होगा .। यह भी ध्यान दें कि -maxdepthएक मानक विकल्प नहीं है ( -pruneहै)।
स्टीफन चेज़लस

2
dotglobविकल्प दिलचस्प है, लेकिन dotglobकेवल के उपयोग पर लागू *find .हमेशा छिपी निर्देशिका (और वर्तमान dir के रूप में)
rubo77

6

वर्तमान निर्देशिका के भीतर दृश्यमान और छिपी हुई निर्देशिकाओं को खोजने के लिए यह किया जाता है, मूल निर्देशिका को छोड़कर:

केवल निर्देशिका के माध्यम से लूप करने के लिए:

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

परिणाम में सिमिलिंक शामिल करने के लिए:

find -L -path './*' -prune -type d

प्रत्येक निर्देशिका के लिए कुछ करने के लिए (सिमिलिंक को छोड़कर):

find -path './*' -prune -type d -print0 | xargs -0 <cmds>

छिपी निर्देशिका को बाहर करने के लिए:

find -path './[^.]*' -prune -type d

लौटाए गए मूल्यों पर कई आदेशों को निष्पादित करने के लिए (एक बहुत ही आकस्मिक उदाहरण):

find -path './[^.]*' -prune -type d -print0 | xargs -0 -I '{}' sh -c \
"printf 'first: %-40s' '{}'; printf 'second: %s\n' '{}'"

'श-सी' के बजाय 'बैश-सी' आदि का भी उपयोग कर सकते हैं।


यदि गूंज * * में 'd' के लिए गूंज * / 'होता है, तो क्या होता है, कहते हैं, 60,000 निर्देशिकाएं?
AsymLabs

आपको "बहुत सारी फाइलें" त्रुटि मिलेंगी लेकिन इसे हल किया जा सकता है: डेबियन में "बहुत सारी खुली हुई फाइलें" को कैसे दरकिनार किया जाए
rubo77

1
Xargs उदाहरण केवल निर्देशिका नाम 9e.g का सबसेट के लिए काम करेगा। रिक्त स्थान या newlines के साथ काम नहीं करेगा)। उपयोग करने के लिए बेहतर है ... -print0 | xargs -0 ...अगर आपको नहीं पता कि सटीक नाम क्या हैं।
एंथन

1
@ rubo77 ने छिपी हुई फ़ाइलों / निर्देशिकाओं और कई आदेशों के निष्पादन को बाहर करने का तरीका जोड़ा - बेशक यह एक स्क्रिप्ट के साथ भी किया जा सकता है।
AsymLabs

1
मैंने नीचे दिए गए अपने उत्तर में एक उदाहरण जोड़ा, कैसे एक फंक्शन का उपयोग करके प्रत्येक डायरेक्टरी को कुछ करना हैfind * | while read file; do ...
rubo77

3

आप सभी निर्देशिकाओं के माध्यम से लूप कर सकते हैं, जिसमें छिपी निर्देशिका (डॉट के साथ शुरुआत) एक लाइन में है और इसके साथ कई कमांड हैं:

for file in */ .*/ ; do echo "$file is a directory"; done

यदि आप सिमिलिंक को बाहर करना चाहते हैं:

for file in *; do 
  if [[ -d "$file" && ! -L "$file" ]]; then
    echo "$file is a directory"; 
  fi; 
done

नोट: सूची का उपयोग */ .*/कार्य में होता है, लेकिन फ़ोल्डर्स को भी प्रदर्शित करता है .और ..zsh में यह इनको नहीं दिखाएगा, लेकिन यदि फ़ोल्डर में कोई छिपी हुई फ़ाइल नहीं है, तो उसे फेंक दें

एक क्लीनर संस्करण जिसमें छिपी निर्देशिका शामिल होगी और बाहर रखा जाएगा .. / डॉटग्लोब विकल्प के साथ होगा:

shopt -s dotglob
for file in */ ; do echo "$file is a directory"; done

(या setopt dotglobzsh में)

आप डॉटग्लोब को परेशान कर सकते हैं

shopt -u dotglob

2

यह सूची में प्रत्येक निर्देशिका में पूरा पथ शामिल करेगा:

for i in $(find $PWD -maxdepth 1 -type d); do echo $i; done

1
रिक्त स्थान के साथ फ़ोल्डर्स का उपयोग करते समय टूट जाता है
एलेजैंड्रो Sazo

0

का प्रयोग करें findसाथ -execनिर्देशिका लूप करने के लिए और एक फोन समारोह कार्यकारी विकल्प में:

dosomething () {
  echo "doing something with $1"
}
export -f dosomething
find -path './*' -prune -type d -exec bash -c 'dosomething "$0"' {} \;

छिपी हुई निर्देशिकाओं का उपयोग करना shopt -s dotglobया shopt -u dotglobशामिल करना / बाहर करना


0

यह दिए गए पथ में उप-निर्देशिका की संख्या के साथ सभी निर्देशिकाओं को सूचीबद्ध करता है:

for directory in */ ; do D=$(readlink -f "$directory") ; echo $D = $(find "$D" -mindepth 1 -type d | wc -l) ; done

-1
ls -d */ | while read d
do
        echo $d
done

This is one directory with spaces in the name- लेकिन कई के रूप में पार्स हो जाता है।
पिस्कवॉर

-5
ls -l | grep ^d

या:

ll | grep ^d

आप इसे एक उपनाम के रूप में सेट कर सकते हैं


1
दुर्भाग्य से, मुझे नहीं लगता कि यह प्रश्न का उत्तर देता है, जो "मैं केवल निर्देशिकाओं के माध्यम से लूप करना चाहता हूं" - जो इस- lsआधारित उत्तर की तुलना में थोड़ा अलग है , जो निर्देशिकाओं को सूचीबद्ध करता है
जेफ स्कालर

1
इसका उत्पादन पार्स करने के लिए एक अच्छा विचार नहीं है ls: mywiki.wooledge.org/ParsingLs
codeforester
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.