बैश स्क्रिप्टिंग: खाली निर्देशिका के लिए परीक्षण


95

यदि कोई निर्देशिका में कोई फ़ाइल नहीं है, तो मैं परीक्षण करना चाहता हूं। यदि हां, तो मैं कुछ प्रोसेसिंग छोड़ दूंगा।

मैंने निम्नलिखित कोशिश की:

if [ ./* == "./*" ]; then
    echo "No new file"
    exit 1
fi

यह निम्नलिखित त्रुटि देता है:

line 1: [: too many arguments

क्या कोई समाधान / विकल्प है?


जवाबों:


120
if [ -z "$(ls -A /path/to/dir)" ]; then
   echo "Empty"
else
   echo "Not Empty"
fi

इसके अलावा, यह जाँचना अच्छा होगा कि क्या निर्देशिका पहले मौजूद है।


11
एक साथ &&और प्रयोग न करें ||! अगर echo "Not Empty"फेल हुआ तो echo "Empty"चलेगा! कोशिश करो echo "test" && false || echo "fail"! हां, मुझे पता है कि मैं echoअसफल नहीं होऊंगा, लेकिन यदि आप किसी अन्य कमांड को बदलते हैं, तो आप आश्चर्यचकित होंगे!
uzsolt

4
कृपया, कम से कम एक उदाहरण प्रदान करें जब ऊपर दिया गया कोड काम नहीं करेगा। अफसोस यह कोड बिल्कुल सही है। मुझे आशा है कि
पूछने वाला

3
[ "$(ls -A /)" ] && touch /non-empty || echo "Empty"- अगर आप गैर-रिक्त डायरियों को "मार्क" करना चाहते हैं non-empty, जिसका नाम बनाई गई फ़ाइल है , तो विफल हो जाएगा और "खाली" प्रिंट करेगा।
uzsolt

4
जहां है touch /emptyमेरी लाइन में?
एंड्री एटापिन

7
अरे नहीं! इस कोड के साथ एक बहुत महत्वपूर्ण समस्या है। यह होना चाहिए if [ -n "$(ls -A /path/to/dir)" ]; then... कृपया उत्तर को अपडेट करने से पहले कोई इस कोड को अपने सर्वर में कहीं और एक हैकर को बताए कि कैसे इसका फायदा उठाया जाए। यदि /path/to/dirखाली नहीं है, तो वहां के फ़ाइलनाम तर्क के रूप में पारित हो जाते हैं, /bin/testजो स्पष्ट रूप से इरादा नहीं है। बस -nतर्क, समस्या हल करें। धन्यवाद!
एडवर्ड नेड हार्वे

21

किसी भी चीज या शेल ग्लब्स को गिनने की जरूरत नहीं है। आप के readसाथ संयोजन में भी उपयोग कर सकते हैं find। यदि findआउटपुट खाली है, तो आप वापस आ जाएंगे false:

if find /some/dir -mindepth 1 | read; then
   echo "dir not empty"
else
   echo "dir empty"
fi

यह पोर्टेबल होना चाहिए।


अच्छा समाधान है, लेकिन मुझे लगता है कि आपकी echoकॉल गलत परिणाम को दर्शाती है: मेरे परीक्षण में (साइग्विन के तहत) find . -mindepth 1 | readएक गैर-खाली डायर में 141 त्रुटि कोड था, और 0 एक खाली डायर में
लुकास साइमन

@LucasCimon यहां नहीं है (macOS और GNU / Linux)। एक गैर-खाली निर्देशिका के लिए, read0 लौटाता है, और एक खाली के लिए, 1.
slhck

1
पीएसए के साथ काम नहीं करता हैset -o pipefail
कर्नल थर्टी दो

19
if [ -n "$(find "$DIR_TO_CHECK" -maxdepth 0 -type d -empty 2>/dev/null)" ]; then
    echo "Empty directory"
else
    echo "Not empty or NOT a directory"
fi

सही और तेज। अच्छा!
l0b0

4
इसे उद्धरण (2x) और -nसही और सुरक्षित होने के लिए परीक्षण की आवश्यकता है ( नाम में रिक्त स्थान के साथ निर्देशिका का परीक्षण करें, इसे '0 = 1' नाम के साथ गैर-रिक्त निर्देशिका के साथ परीक्षण करें)। ... [ -n "$(find "$DIR_TO_CHECK" -maxdepth 0 -type d -empty 2>/dev/null)" ]; ...
ज़रीन

1
@ivan_pozdeev यह सच नहीं है, कम से कम जीएनयू खोजने के लिए। आप सोच रहे होंगे grepserverfault.com/questions/225798/…
व्लादिमीर पेंटेलेव

यह लिखना सरल हो सकता है find "$DIR_TO_CHECK" -maxdepth 0 -type d -empty | grep .और grep से बाहर निकलने की स्थिति पर भरोसा कर सकता है । आप इसे जिस भी तरीके से करते हैं, यह इस सवाल का सही जवाब है।
टॉम एंडरसन

13
#!/bin/bash
if [ -d /path/to/dir ]; then
    # the directory exists
    [ "$(ls -A /path/to/dir)" ] && echo "Not Empty" || echo "Empty"
else
    # You could check here if /path/to/dir is a file with [ -f /path/to/dir]
fi

4
यह होना चाहिए, पार्सिंग एलएस आउटपुट की कोई आवश्यकता नहीं है, बस देखें कि यह खाली है या नहीं। खोज का उपयोग करना मुझे एक ओवरकिल की तरह लगता है।
अकोस्टादीनोव

4

यह वर्तमान कार्यशील निर्देशिका (।) में काम करेगा:

[ `ls -1A . | wc -l` -eq 0 ] && echo "Current dir is empty." || echo "Current dir has files (or hidden files) in it."

या एक ही कमांड को तीन पंक्तियों में विभाजित करने के लिए अधिक पठनीय होना चाहिए:

[ `ls -1A . | wc -l` -eq 0 ] && \
echo "Current dir is empty." || \
echo "Current dir has files (or hidden files) in it."

बस की जगह ls -1A . | wc -lके साथ ls -1A <target-directory> | wc -lकरता है, तो आप एक अलग लक्ष्य फ़ोल्डर पर इसे चलाने के लिए की जरूरत है।

संपादित करें : मैंने प्रतिस्थापित -1aकिया -1A(देखें @Daniel टिप्पणी)


2
ls -Aइसके बजाय का उपयोग करें । कुछ फ़ाइल सिस्टम में डॉक्स के अनुसार .और ..प्रतीकात्मक लिंक नहीं हैं ।
डैनियल बेक

1
धन्यवाद @Daniel, मैंने आपके सुझाव के बाद अपना जवाब संपादित किया। मुझे पता है कि "1" को भी हटाया जा सकता है।
ztank1013

2
यह चोट नहीं करता है, लेकिन अगर यह एक टर्मिनल के लिए उत्पादन नहीं है यह निहित है। चूंकि आप इसे किसी अन्य प्रोग्राम में पाइप करते हैं, इसलिए यह बेमानी है।
डैनियल बेक

-1निश्चित ही बेमानी है। यहां तक ​​कि अगर lsएक पाइप प्रति पंक्ति जब वह पाइप किया जाएगा तब भी मुद्रित नहीं होगा, तो यह शून्य या अधिक लाइनों का उत्पादन करने पर जाँच के विचार को प्रभावित नहीं करता है।
विक्टर यारमा

3

निम्न का उपयोग करें:

count="$( find /path -mindepth 1 -maxdepth 1 | wc -l )"
if [ $count -eq 0 ] ; then
   echo "No new file"
   exit 1
fi

इस तरह, आप आउटपुट स्वरूप से स्वतंत्र हैं ls-mindepthनिर्देशिका को ही छोड़ देता है, -maxdepthचीजों को गति देने के लिए उपनिर्देशिका में पुनरावर्ती रूप से बचाव करने से रोकता है।


बेशक, आप अब पर निर्भर कर रहे हैं wc -lऔर findउत्पादन प्रारूप (जो हालांकि काफी सादा है)।
डैनियल बेक

3

एक सरणी का उपयोग करना:

files=( * .* )
if (( ${#files[@]} == 2 )); then
    # contents of files array is (. ..)
    echo dir is empty
fi

3
बहुत अच्छा समाधान, लेकिन ध्यान दें कि इसके लिएshopt -s nullglob
xebeche

3
यह ${#files[@]} == 2धारणा रूट डायर के लिए नहीं है (आप शायद परीक्षण नहीं करेंगे यदि यह खाली है लेकिन कुछ कोड जो उस सीमा के बारे में नहीं जानते हैं)।
ivan_pozdeev

3

हैकी, लेकिन बैश-ओनली, पीआईडी-फ्री तरीका:

is_empty() {
    test -e "$1/"* 2>/dev/null
    case $? in
        1)   return 0 ;;
        *)   return 1 ;;
    esac
}

यह इस तथ्य का लाभ उठाता है कि testअगर एक से अधिक तर्क दिए गए तो बिलिन 2 से बाहर निकलता है -e: सबसे पहले, "$1"/*ग्लब को बैश द्वारा विस्तारित किया जाता है। इसका परिणाम प्रति फ़ाइल एक तर्क है। इसलिए

  • यदि कोई फ़ाइल नहीं हैं, तो तारांकन test -e "$1"*विस्तृत नहीं होता है, इसलिए शेल नाम की फ़ाइल की कोशिश में वापस आ जाता है *, जो 1 देता है।

  • ... सिवाय अगर वास्तव में एक फ़ाइल है जिसका नाम ठीक है *, तो तारांकन अच्छी तरह से फैलता है, तारांकन, जो ऊपर के समान कॉल के रूप में समाप्त होता है, अर्थात। test -e "dir/*", बस यह समय 0. लौटाता है (यह इंगित करने के लिए धन्यवाद @ धन्यवाद)

  • यदि कोई एक फ़ाइल है, test -e "dir/file"चलाया जाता है, जो 0 देता है।

  • लेकिन अगर 1 से अधिक फाइलें हैं, test -e "dir/file1" "dir/file2" तो चलाया जाता है, जो इसे उपयोग त्रुटि के रूप में रिपोर्ट करता है, अर्थात 2।

case पूरे तर्क को चारों ओर से लपेटता है ताकि केवल पहला मामला, 1 निकास की स्थिति को सफलता के रूप में रिपोर्ट किया जाए।

संभावित समस्याएं जिनकी मैंने जाँच नहीं की है:

  • अनुमत तर्कों की संख्या से अधिक फाइलें हैं - मुझे लगता है कि यह 2+ फाइलों के साथ मामले के समान व्यवहार कर सकता है।

  • या वास्तव में एक खाली नाम के साथ फ़ाइल है - मुझे यकीन नहीं है कि यह किसी भी ओएस ओएस / एफएस पर संभव है।


1
मामूली सुधार: यदि dir / में कोई फ़ाइल नहीं है, तो test -e dir/*कहा जाता है। यदि केवल फ़ाइल '*' है तो dir में होगी। परीक्षण 0. वापस आ जाएगा। यदि अधिक फाइलें हैं, तो यह 2 वापस आती है। इसलिए यह वर्णित के अनुसार काम करता है।
TrueY

आप सही हैं, @ सही, मैंने उत्तर में इसे शामिल किया है। धन्यवाद!
Alois Mahdal

2

FIND (1) (लिनक्स और फ्रीबीएसडी के तहत) आप "-maxdepth 0" के माध्यम से एक निर्देशिका प्रविष्टि में गैर-पुनरावर्ती रूप से देख सकते हैं और परीक्षण कर सकते हैं कि क्या यह "-empty" के साथ खाली है। इस प्रश्न पर लागू होता है:

if test -n "$(find ./ -maxdepth 0 -empty)" ; then
    echo "No new file"
    exit 1
fi

यह 100% पोर्टेबल नहीं हो सकता है, लेकिन यह सुरुचिपूर्ण है।
क्रेग रिंगर

1

मुझे लगता है कि सबसे अच्छा समाधान है:

files=$(shopt -s nullglob; shopt -s dotglob; echo /MYPATH/*)
[[ "$files" ]] || echo "dir empty" 

आभार https://stackoverflow.com/a/91558/520567

यह मेरे उत्तर का एक गुमनाम संपादन है जो किसी के लिए सहायक हो सकता है या नहीं भी हो सकता है: एक मामूली परिवर्तन फ़ाइलों की संख्या देता है:

files=$(shopt -s nullglob dotglob; s=(MYPATH/*); echo ${s[*]}) 
echo "MYPATH contains $files files"

यह सही ढंग से काम करेगा भले ही फ़ाइलनाम में स्थान हो।


1
if find "${DIR}" -prune ! -empty -exit 1; then
    echo Empty
else
    echo Not Empty
fi

संपादित करें: मुझे लगता है कि कार्यान्वयन पर त्वरित नज़र डालने के बाद, यह समाधान ग्नू खोज के साथ ठीक काम करता है । लेकिन यह उदाहरण के लिए, netbsd की खोज के साथ काम नहीं कर सकता है । दरअसल, वह स्टेट (2) के st_size फ़ील्ड का उपयोग करता है। मैनुअल इसका वर्णन करता है:

st_size            The size of the file in bytes.  The meaning of the size
                   reported for a directory is file system dependent.
                   Some file systems (e.g. FFS) return the total size used
                   for the directory metadata, possibly including free
                   slots; others (notably ZFS) return the number of
                   entries in the directory.  Some may also return other
                   things or always report zero.

एक बेहतर समाधान भी सरल है:

if find "${DIR}" -mindepth 1 -exit 1; then
    echo Empty
else
    echo Not Empty
fi

इसके अलावा, 1 समाधान में -प्रयोग बेकार है।

EDIT: gnu find के लिए no -exit .. ऊपर का समाधान NetBSD की खोज के लिए अच्छा है। GNU खोजने के लिए, यह काम करना चाहिए:

if [ -z "`find \"${DIR}\" -mindepth 1 -exec echo notempty \; -quit`" ]; then
    echo Empty
else
    echo Not Empty
fi

लगता है से जीएनयू findutils 4.6.0 (नवीनतम संस्करण) एक नहीं है -exitविधेय
डेनिस

0

यह सब महान सामग्री है - बस इसे एक स्क्रिप्ट में बनाया गया है ताकि मैं वर्तमान के नीचे खाली निर्देशिकाओं की जांच कर सकूं। नीचे 'फाइडेमिप्ट' नामक एक फाइल डालनी चाहिए, जिसे रास्ते में रखा जाए ताकि बैश उसे मिल जाए और फिर उसे चलाने के लिए 755 पर चाम करें। आसानी से आपकी विशिष्ट आवश्यकताओं में संशोधन किया जा सकता है जो मुझे लगता है।

#!/bin/bash
if [ "$#" == "0" ]; then 
find . -maxdepth 1 -type d -exec findempty "{}"  \;
exit
fi

COUNT=`ls -1A "$*" | wc -l`
if [ "$COUNT" == "0" ]; then 
echo "$* : $COUNT"
fi

0

मेरे लिए यह काम, निर्देशिका में फ़ाइलों की जांच और प्रोसेस करना ../IN, स्क्रिप्ट पर विचार करना है ../Script:

FileTotalCount=0

    for file in ../IN/*; do
    FileTotalCount=`expr $FileTotalCount + 1`
done

if test "$file" = "../IN/*"
then

    echo "EXITING: NO files available for processing in ../IN directory. "
    exit

else

  echo "Starting Process: Found ""$FileTotalCount"" files in ../IN directory for processing."

# Rest of the Code

0

अगर निर्देशिका मौजूद है और परीक्षण में खाली है तो क्या होगा यदि कथन नहीं है

if [[ -d path/to/dir && -n "$(ls -A path/to/dir)" ]]; then 
  echo "directory exists"
else
  echo "directory doesn't exist"
fi

-1

वर्तमान एक के अलावा किसी भी निर्देशिका के लिए, यदि आप इसे खाली करने की कोशिश कर रहे rmdirहैं, तो यह rmdirदेख सकते हैं कि गैर-खाली निर्देशिका के लिए विफल होने की गारंटी है। यदि rmdirसफल होता है, और आप वास्तव में परीक्षण से बचने के लिए खाली निर्देशिका चाहते थे, तो बस mkdirफिर से।

इस हैक का उपयोग न करें यदि ऐसी अन्य प्रक्रियाएं हैं जो एक निर्देशिका द्वारा अस्वीकृत हो सकती हैं जो उन्हें संक्षिप्त रूप से मौजूद रहने के बारे में पता है।

यदि rmdirआप के लिए काम नहीं करेगा, और आप निर्देशिकाओं का परीक्षण कर सकते हैं जिसमें बड़ी संख्या में फाइलें हो सकती हैं, तो शेल ग्लोबिंग पर निर्भर कोई भी समाधान धीमा हो सकता है और / या कमांड लाइन की लंबाई सीमा में चला सकता है। शायद findउस मामले में उपयोग करने के लिए बेहतर है । सबसे तेज findसमाधान मैं इस तरह से सोच सकता हूं

is_empty() {
    test -z $(find "$1" -mindepth 1 -printf X -quit)
}

यह GNU और BSD संस्करणों के लिए काम करता है, findलेकिन सोलारिस एक के लिए नहीं, जो उन findऑपरेटरों में से हर एक को याद कर रहा है । अपने काम से प्यार करो, ओरेकल।


अच्छा विचार नहीं। ओपी बस यह परखना चाहता था कि निर्देशिका खाली थी या नहीं।
रोइमा

-3

आप निर्देशिका को हटाने और एक त्रुटि की प्रतीक्षा करने का प्रयास कर सकते हैं; खाली नहीं होने पर rmdir डायरेक्टरी को डिलीट नहीं करेगा।

_path="some/path"
if rmdir $_path >/dev/null 2>&1; then
   mkdir $_path        # create it again
   echo "Empty"
else
   echo "Not empty or doesn't exist"
fi

3
-1 यह एक तरह का कोड है जो बैकफायर करता है। rmdirअगर मुझे निर्देशिका को हटाने की कोई अनुमति नहीं है तो मैं असफल हो जाऊंगा; या अगर यह एक Btrfs सबवोल्यूम है; या यदि यह केवल पढ़ने के लिए फाइल सिस्टम के अंतर्गत आता है। और अगर rmdirविफल नहीं होता है और mkdirचलता है: क्या होगा यदि पहले से हटा दी गई निर्देशिका किसी अन्य उपयोगकर्ता की हो? इसकी (संभवतः गैर-मानक) अनुमतियों के बारे में क्या? एसीएल? विस्तारित विशेषताएँ? सब हार गए।
कामिल मैकियोरोस्की

ठीक है, मैं सिर्फ बैश सीख रहा हूं और मैंने सोचा कि यह सभी निर्देशिका के माध्यम से पुनरावृति के बजाय एक तेज़ तरीका हो सकता है, लेकिन सीपीयू शक्तिशाली हैं और आप सही हैं, सुरक्षित नहीं हैं।
इम्पेक्स
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.