मेरा जवाब है:
function emptydir {
[ "$1/"* "" = "" ] 2> /dev/null &&
[ "$1/"..?* "" = "" ] 2> /dev/null &&
[ "$1/".[^.]* "" = "" ] 2> /dev/null ||
[ "$1/"* = "$1/*" ] 2> /dev/null && [ ! -e "$1/*" ] &&
[ "$1/".[^.]* = "$1/.[^.]*" ] 2> /dev/null && [ ! -e "$1/.[^.]*" ] &&
[ "$1/"..?* = "$1/..?*" ] 2> /dev/null && [ ! -e "$1/..?*" ]
}
यह POSIX आज्ञाकारी है, और यह नहीं कि यह बहुत मायने रखता है, यह आमतौर पर उस समाधान की तुलना में तेज़ है जो निर्देशिका को सूचीबद्ध करता है और आउटपुट को गपशप करने के लिए पाइप करता है।
उपयोग:
if emptydir adir
then
echo "nothing found"
else
echo "not empty"
fi
मुझे उत्तर https://unix.stackexchange.com/a/202276/160204 पसंद है , जिसे मैं इस रूप में फिर से लिखता हूं:
function emptydir {
! { ls -1qA "./$1/" | grep -q . ; }
}
यह निर्देशिका को सूचीबद्ध करता है और परिणाम को संक्षिप्त करने के लिए पाइप करता है। इसके बजाय, मैं एक साधारण फ़ंक्शन का प्रस्ताव करता हूं जो ग्लोब विस्तार और तुलना पर आधारित है।
function emptydir {
[ "$(shopt -s nullglob; echo "$1"/{,.[^.],..?}*)" = "" ]
}
यह फ़ंक्शन मानक POSIX नहीं है और इसके साथ एक सबहेल कॉल करता है $()
। मैं इस सरल कार्य को पहले समझाता हूं ताकि हम अंतिम समाधान को बेहतर ढंग से समझ सकें (बाद में tldr उत्तर देखें)।
स्पष्टीकरण:
बाएं हाथ की ओर (LHS) खाली है जब कोई विस्तार नहीं होता है, जो कि ऐसा होता है जब निर्देशिका खाली होती है। नलग्लोब विकल्प की आवश्यकता है क्योंकि अन्यथा जब कोई मैच नहीं होता है, तो गोला ही विस्तार का परिणाम है। (RHS होने पर LHS के ग्लोब से मेल खाता है, जब निर्देशिका खाली होती है तो झूठी सकारात्मकता के कारण काम नहीं करता है, जब LHS ग्लोब ग्लोब के रूप में नामित एकल फ़ाइल से मेल खाता है: *
ग्लोब *
में फ़ाइल नाम के विकल्प में मेल खाता है । ) ब्रेस अभिव्यक्ति {,.[^.],..?}
छिपी हुई फ़ाइलों को कवर करती है, लेकिन नहीं ..
या नहीं .
।
क्योंकि shopt -s nullglob
अंदर $()
(एक उपधारा) निष्पादित किया जाता है , यह nullglob
वर्तमान शेल के विकल्प को नहीं बदलता है , जो सामान्य रूप से एक अच्छी बात है। दूसरी ओर, इस विकल्प को स्क्रिप्ट में सेट करना एक अच्छा विचार है, क्योंकि जब कोई मैच नहीं होता है, तो एक ग्लोब रिटर्न कुछ होने की त्रुटि होती है। इसलिए, कोई स्क्रिप्ट की शुरुआत में नलग्लोब विकल्प सेट कर सकता है और फ़ंक्शन में इसकी आवश्यकता नहीं होगी। आइए इसे ध्यान में रखें: हम एक समाधान चाहते हैं जो नलग्लोब विकल्प के साथ काम करता है।
चेतावनियां:
यदि हमारे पास निर्देशिका तक पहुंच नहीं है, तो फ़ंक्शन उसी तरह रिपोर्ट करता है जैसे कि कोई खाली निर्देशिका थी। यह उस फ़ंक्शन पर भी लागू होता है जो निर्देशिका को सूचीबद्ध करता है और आउटपुट को grep करता है।
shopt -s nullglob
आदेश मानक POSIX नहीं है।
यह द्वारा बनाए गए उपधारा का उपयोग करता है $()
। यह बड़ी बात नहीं है, लेकिन अगर हम इससे बच सकते हैं तो अच्छा है।
समर्थक:
ऐसा नहीं है कि यह वास्तव में मायने रखता है, लेकिन यह फ़ंक्शन पिछले एक की तुलना में चार गुना तेज है, प्रक्रिया के भीतर कर्नेल में बिताए गए सीपीयू समय की मात्रा के साथ मापा जाता है।
अन्य उपाय:
हम shopt -s nullglob
LHS पर गैर POSIX कमांड को हटा सकते हैं और स्ट्रिंग "$1/* $1/.[^.]* $1/..?*"
को RHS में डाल सकते हैं और अलग-अलग झूठी सकारात्मकता को समाप्त कर सकते हैं जो तब होती हैं जब हमारे पास केवल नाम वाली फाइलें होती हैं '*'
, .[^.]*
या ..?*
निर्देशिका में होती है:
function emptydir {
[ "$(echo "$1"/{,.[^.],..?}*)" = "$1/* $1/.[^.]* $1/..?*" ] &&
[ ! -e "$1/*" ] && [ ! -e "$1/.[^.]*" ] && [ ! -e "$1/..?*" ]
}
shopt -s nullglob
कमांड के बिना , यह अब उपधारा को हटाने के लिए समझ में आता है, लेकिन हमें सावधान रहना होगा क्योंकि हम शब्द विभाजन से बचना चाहते हैं और फिर भी एलएचएस पर ग्लोब विस्तार की अनुमति देते हैं। विशेष रूप से शब्द विभाजन से बचने के लिए उद्धृत करने से काम नहीं चलता है, क्योंकि यह ग्लोब विस्तार को भी रोकता है। हमारे समाधान के लिए ग्लब्स पर अलग से विचार करना है:
function emptydir {
[ "$1/"* = "$1/*" ] 2> /dev/null && [ ! -e "$1/*" ] &&
[ "$1/".[^.]* = "$1/.[^.]*" ] 2> /dev/null && [ ! -e "$1/.[^.]*" ] &&
[ "$1/"..?* = "$1/..?*" ] 2> /dev/null && [ ! -e "$1/..?*" ]
}
हमारे पास अभी भी व्यक्तिगत ग्लोब के लिए शब्द विभाजन है, लेकिन यह अब ठीक है, क्योंकि यह केवल एक त्रुटि के परिणामस्वरूप होगा जब निर्देशिका खाली नहीं होगी। LHS पर दिए गए ग्लोब से मेल खाती कई फाइलें होने पर हमने त्रुटि संदेश को छोड़ने के लिए 2> / dev / null जोड़ा।
हमें याद है कि हम एक समाधान चाहते हैं जो नलग्लोब विकल्प के साथ भी काम करता है। उपरोक्त समाधान नलग्लोब विकल्प के साथ विफल हो जाता है, क्योंकि जब निर्देशिका खाली होती है, तो एलएचएस भी खाली होता है। सौभाग्य से, यह कभी नहीं कहता कि निर्देशिका खाली है जब यह नहीं है। यह केवल यह कहने में विफल है कि यह कब है खाली है। इसलिए, हम nullglob विकल्प को अलग से प्रबंधित कर सकते हैं। हम केवल मामलों [ "$1/"* = "" ]
आदि को जोड़ नहीं सकते क्योंकि ये विस्तार के रूप में होंगे [ = "" ]
, आदि जो वाक्य-रचना के गलत हैं। इसलिए, हम [ "$1/"* "" = "" ]
इसके बजाय आदि का उपयोग करते हैं। हमें फिर से तीन मामलों पर विचार करना है *
, ..?*
और .[^.]*
छिपी हुई फ़ाइलों का मिलान करना है, लेकिन नहीं .
और..
। यदि हमारे पास नलग्लोब विकल्प नहीं है, तो ये हस्तक्षेप नहीं करेंगे, क्योंकि वे यह भी कभी नहीं कहते हैं कि जब यह नहीं है तो यह खाली है। तो, अंतिम प्रस्तावित समाधान है:
function emptydir {
[ "$1/"* "" = "" ] 2> /dev/null &&
[ "$1/"..?* "" = "" ] 2> /dev/null &&
[ "$1/".[^.]* "" = "" ] 2> /dev/null ||
[ "$1/"* = "$1/*" ] 2> /dev/null && [ ! -e "$1/*" ] &&
[ "$1/".[^.]* = "$1/.[^.]*" ] 2> /dev/null && [ ! -e "$1/.[^.]*" ] &&
[ "$1/"..?* = "$1/..?*" ] 2> /dev/null && [ ! -e "$1/..?*" ]
}
सुरक्षा चिंता:
दो फाइलें rm
और x
एक खाली निर्देशिका बनाएं और *
प्रॉम्प्ट पर निष्पादित करें। ग्लोब *
का विस्तार होगा rm x
और इसे हटाने के लिए निष्पादित किया जाएगा x
। यह सुरक्षा चिंता नहीं है, क्योंकि हमारे कार्य में, ग्लब्स स्थित हैं जहां विस्तार को कमांड के रूप में नहीं देखा जाता है, लेकिन तर्क के रूप में, जैसे कि for f in *
।