التحقق من البرنامج النصي Shell إذا كان الدليل يحتوي على ملفات
سؤال
من برنامج شل، كيف يمكنني التحقق مما إذا كان الدليل يحتوي على ملفات؟
شيء مشابه لهذا
if [ -e /some/dir/* ]; then echo "huzzah"; fi;
ولكنه يعمل إذا كان الدليل يحتوي على ملف واحد أو عدة ملفات (الملف أعلاه يعمل فقط مع 0 أو 1 ملف بالضبط).
المحلول
الحلول المستخدمة حتى الآن ls
.إليك حل bash بالكامل:
#!/bin/bash
shopt -s nullglob dotglob # To include hidden files
files=(/some/dir/*)
if [ ${#files[@]} -gt 0 ]; then echo "huzzah"; fi
نصائح أخرى
أفضل ثلاث حيل
shopt -s nullglob dotglob; f=your/dir/*; ((${#f}))
هذه الخدعة 100% bash
ويستدعي (يولد) قذيفة فرعية.الفكرة من برونو دي فرين وتحسينها com.teambobتعليق.
files=$(shopt -s nullglob dotglob; echo your/dir/*)
if (( ${#files} ))
then
echo "contains files"
else
echo "empty (or does not exist or is a file)"
fi
ملحوظة: لا يوجد فرق بين الدليل الفارغ والدليل غير الموجود (وحتى عندما يكون المسار المقدم ملفًا).
يوجد بديل مشابه ومزيد من التفاصيل (والمزيد من الأمثلة) على 'رسمي' الأسئلة الشائعة لقناة #bash على IRC:
if (shopt -s nullglob dotglob; f=(*); ((${#f[@]})))
then
echo "contains files"
else
echo "empty (or does not exist, or is a file)"
fi
[ -n "$(ls -A your/dir)" ]
هذه الخدعة مستوحاة من مقالة nixCraft نشرت في عام 2007.يضيف 2>/dev/null
لقمع خطأ الإخراج "No such file or directory"
.
أنظر أيضا أندرو تايلورإجابة (2008) و gr8can8dianإجابة (2011).
if [ -n "$(ls -A your/dir 2>/dev/null)" ]
then
echo "contains files (or is a file)"
else
echo "empty (or does not exist)"
fi
أو نسخة الباشيّة ذات السطر الواحد:
[[ $(ls -A your/dir) ]] && echo "contains files" || echo "empty"
ملحوظة: ls
عائدات $?=2
عندما لا يكون الدليل موجودا.ولكن لا يوجد فرق بين الملف والدليل الفارغ.
[ -n "$(find your/dir -prune -empty)" ]
هذه الحيلة الأخيرة مستوحاة من إجابة جرافستار أين -maxdepth 0
لقد بدل بواسطة -prune
وتحسينها فيلستعليق.
if [ -n "$(find your/dir -prune -empty 2>/dev/null)" ]
then
echo "empty (directory or file)"
else
echo "contains files (or does not exist)"
fi
الاختلاف باستخدام -type d
:
if [ -n "$(find your/dir -prune -empty -type d 2>/dev/null)" ]
then
echo "empty directory"
else
echo "contains files (or does not exist or is not a directory)"
fi
توضيح:
find -prune
يشبه منfind -maxdepth 0
باستخدام أحرف أقلfind -empty
طباعة الدلائل والملفات الفارغةfind -type d
طباعة الدلائل فقط
ملحوظة: يمكنك أيضًا استبدال [ -n "$(find your/dir -prune -empty)" ]
فقط عن طريق النسخة المختصرة أدناه:
if [ `find your/dir -prune -empty 2>/dev/null` ]
then
echo "empty (directory or file)"
else
echo "contains files (or does not exist)"
fi
يعمل هذا الرمز الأخير في معظم الحالات ولكن انتبه إلى أن المسارات الضارة قد تعبر عن أمر ما...
ماذا عن ما يلي:
if find /some/dir/ -maxdepth 0 -empty | read v; then echo "Empty dir"; fi
بهذه الطريقة ليست هناك حاجة لإنشاء قائمة كاملة بمحتويات الدليل.ال read
هو تجاهل المخرجات وجعل التعبير يتم تقييمه على أنه صحيح فقط عند قراءة شيء ما (على سبيل المثال. /some/dir/
تم العثور عليها فارغة بواسطة find
).
يحاول:
if [ ! -z `ls /some/dir/*` ]; then echo "huzzah"; fi
# Works on hidden files, directories and regular files
### isEmpty()
# This function takes one parameter:
# $1 is the directory to check
# Echoes "huzzah" if the directory has files
function isEmpty(){
if [ "$(ls -A $1)" ]; then
echo "huzzah"
else
echo "has no files"
fi
}
اعتني بالدلائل التي تحتوي على الكثير من الملفات!قد يستغرق الأمر بعض الوقت لتقييم ls
يأمر.
IMO الحل الأفضل هو الذي يستخدم
find /some/dir/ -maxdepth 0 -empty
DIR="/some/dir"
if [ "$(ls -A $DIR)" ]; then
echo 'There is something alive in here'
fi
هل يمكنك مقارنة مخرجات هذا؟
ls -A /some/dir | wc -l
# Checks whether a directory contains any nonhidden files. # # usage: if isempty "$HOME"; then echo "Welcome home"; fi # isempty() { for _ief in $1/*; do if [ -e "$_ief" ]; then return 1 fi done return 0 }
بعض ملاحظات التنفيذ:
- ال
for
حلقة تتجنب الاتصال بمصدر خارجيls
عملية.فإنه لا يزال يقرأ كافة إدخالات الدليل مرة واحدة.لا يمكن تحسين ذلك إلا عن طريق كتابة برنامج C يستخدم readdir() بشكل صريح. - ال
test -e
داخل الحلقة يلتقط حالة الدليل الفارغ، وفي هذه الحالة المتغير_ief
سيتم تعيين القيمة "somedir/*".فقط في حالة وجود هذا الملف، ستعيد الدالة "غير فارغ" - ستعمل هذه الوظيفة في جميع تطبيقات POSIX.لكن انتبه إلى أن Solaris /bin/sh لا يندرج ضمن هذه الفئة.إنه
test
التنفيذ لا يدعم-e
علَم.
يخبرني هذا إذا كان الدليل فارغًا أو إذا لم يكن كذلك، يخبرني بعدد الملفات التي يحتوي عليها.
directory="/some/dir"
number_of_files=$(ls -A $directory | wc -l)
if [ "$number_of_files" == "0" ]; then
echo "directory $directory is empty"
else
echo "directory $directory contains $number_of_files files"
fi
قد يكون هذا ردًا متأخرًا حقًا ولكن إليك الحل الناجح.هذا الخط يتعرف فقط على وجود الملفات!لن يعطيك نتيجة إيجابية كاذبة في حالة وجود أدلة.
if find /path/to/check/* -maxdepth 0 -type f | read
then echo "Files Exist"
fi
أنا مندهش دليل Wooledge على الدلائل الفارغة لم يتم ذكرها.هذا الدليل، وكل كتاب Wooledge حقًا، يجب قراءته للأسئلة المتعلقة بنوع الصدفة.
ملاحظة من تلك الصفحة:
لا تحاول أبدًا تحليل إخراج ls.حتى حلول ls -A يمكن أن تنكسر (على سبيل المثال.على HP -UX ، إذا كنت جذرًا ، فإن ls -a تقوم بالعكس تمامًا لما يفعله إذا لم تكن جذرًا -ولا ، لا يمكنني تكوين شيء غبي بشكل لا يصدق).
في الواقع، قد يرغب المرء في تجنب السؤال المباشر تمامًا.عادة ما يريدون الناس معرفة ما إذا كان الدليل فارغًا لأنهم يريدون فعل شيء ينطوي على الملفات فيه ، إلخ.انظر إلى السؤال الأكبر.على سبيل المثال، قد يكون أحد هذه الأمثلة القائمة على البحث حلاً مناسبًا:
# Bourne
find "$somedir" -type f -exec echo Found unexpected file {} \;
find "$somedir" -maxdepth 0 -empty -exec echo {} is empty. \; # GNU/BSD
find "$somedir" -type d -empty -exec cp /my/configfile {} \; # GNU/BSD
في أغلب الأحيان، كل ما هو مطلوب حقًا هو شيء مثل هذا:
# Bourne
for f in ./*.mpg; do
test -f "$f" || continue
mympgviewer "$f"
done
بمعنى آخر ، قد يكون الشخص الذي يطرح السؤال قد اعتقد أنه كان هناك حاجة إلى اختبار صريح للدخل الفارغ لتجنب رسالة خطأ مثل MyMPGViewer:./*.ميلا في الغالون:لا يوجد مثل هذا الملف أو الدليل في الواقع لا يوجد مثل هذا الاختبار مطلوب.
dir_is_empty() {
[ "${1##*/}" = "*" ]
}
if dir_is_empty /some/dir/* ; then
echo "huzzah"
fi
افترض أنه ليس لديك ملف اسمه *
داخل /any/dir/you/check
, ، ينبغي أن تعمل على bash
dash
posh
busybox sh
و zsh
ولكن (لZSH) تتطلب unsetopt nomatch
.
يجب أن تكون العروض قابلة للمقارنة بأي منها ls
التي تستخدم *
(glob)، أعتقد أنه سيكون بطيئًا في الدلائل التي تحتوي على العديد من العقد (my /usr/bin
مع أكثر من 3000 ملف لم يكن بطيئًا)، سيستخدم على الأقل ذاكرة كافية لتخصيص جميع dirs/أسماء الملفات (وأكثر) حيث يتم تمريرها جميعًا (حلها) إلى الوظيفة كوسيطات، ربما يكون لدى بعض الأصداف حدود على عدد الوسائط و / أو طول الوسائط.
سيكون من الجيد الحصول على طريقة محمولة سريعة O(1) صفرية للموارد للتحقق مما إذا كان الدليل فارغًا.
تحديث
الإصدار أعلاه لا يأخذ في الاعتبار الملفات/الأديرة المخفية، في حالة الحاجة إلى المزيد من الاختبارات، مثل is_empty
من حيل ريتش (POSIX Shell).:
is_empty () (
cd "$1"
set -- .[!.]* ; test -f "$1" && return 1
set -- ..?* ; test -f "$1" && return 1
set -- * ; test -f "$1" && return 1
return 0 )
ولكن بدلاً من ذلك أفكر في شيء مثل هذا:
dir_is_empty() {
[ "$(find "$1" -name "?*" | dd bs=$((${#1}+3)) count=1 2>/dev/null)" = "$1" ]
}
بعض القلق بشأن اختلافات الخطوط المائلة اللاحقة عن الوسيطة ومخرجات البحث عندما يكون dir فارغًا، وأسطرًا جديدة زائدة (ولكن يجب أن يكون من السهل التعامل مع هذا)، للأسف على بلدي busybox
sh
أظهر ما هو على الأرجح خطأ في find -> dd
تم اقتطاع الأنبوب مع الإخراج بشكل عشوائي (إذا استخدمت cat
يبدو أن الإخراج هو نفسه دائمًا dd
مع الحجة count
).
اختلاف صغير من الجواب برونو:
files=$(ls -1 /some/dir| wc -l)
if [ $files -gt 0 ]
then
echo "Contains files"
else
echo "Empty"
fi
إنه يعمل بالنسبة لي
زش
أعلم أن السؤال تم تحديده لـ bash؛ولكن، للإشارة فقط، ل zsh المستخدمين:
اختبار الدليل غير الفارغ
للتحقق مما إذا foo
غير فارغ:
$ for i in foo(NF) ; do ... ; done
أين إذا foo
غير فارغ، الكود الموجود في for
سيتم تنفيذ الكتلة.
اختبار للدليل الفارغ
للتحقق مما إذا foo
فارغ:
$ for i in foo(N/^F) ; do ... ; done
أين إذا foo
فارغ، الكود الموجود في for
سيتم تنفيذ الكتلة.
ملحوظات
لم نكن بحاجة إلى اقتباس الدليل foo
أعلاه، ولكن يمكننا القيام بذلك إذا كنا بحاجة إلى:
$ for i in 'some directory!'(NF) ; do ... ; done
يمكننا أيضًا اختبار أكثر من كائن، حتى لو لم يكن دليلاً:
$ mkdir X # empty directory
$ touch f # regular file
$ for i in X(N/^F) f(N/^F) ; do echo $i ; done # echo empty directories
X
سيتم تجاهل أي شيء ليس دليلاً.
إضافات
نظرًا لأننا نتحرك، يمكننا استخدام أي كرة (أو توسيع قوس):
$ mkdir X X1 X2 Y Y1 Y2 Z
$ touch Xf # create regular file
$ touch X1/f # directory X1 is not empty
$ touch Y1/.f # directory Y1 is not empty
$ ls -F # list all objects
X/ X1/ X2/ Xf Y/ Y1/ Y2/ Z/
$ for i in {X,Y}*(N/^F); do printf "$i "; done; echo # print empty directories
X X2 Y Y2
يمكننا أيضًا فحص الكائنات الموضوعة في مصفوفة.مع الدلائل على النحو الوارد أعلاه، على سبيل المثال:
$ ls -F # list all objects
X/ X1/ X2/ Xf Y/ Y1/ Y2/ Z/
$ arr=(*) # place objects into array "arr"
$ for i in ${^arr}(N/^F); do printf "$i "; done; echo
X X2 Y Y2 Z
وبالتالي، يمكننا اختبار الكائنات التي قد تم تعيينها بالفعل في معلمة صفيف.
لاحظ أن الكود الموجود في for
من الواضح أن الكتلة يتم تنفيذها على كل دليل على حدة.إذا لم يكن ذلك مرغوبًا، فيمكنك ببساطة ملء معلمة صفيف ثم العمل على تلك المعلمة:
$ for i in *(NF) ; do full_directories+=($i) ; done
$ do_something $full_directories
توضيح
لمستخدمي zsh هناك (F)
تصفيات الكرة الأرضية (انظر man zshexpn
)، الذي يطابق الدلائل "الكاملة" (غير الفارغة):
$ mkdir X Y
$ touch Y/.f # Y is now not empty
$ touch f # create a regular file
$ ls -dF * # list everything in the current directory
f X/ Y/
$ ls -dF *(F) # will list only "full" directories
Y/
المؤهل (F)
يسرد الكائنات المطابقة:هو دليل وليس فارغا.لذا، (^F)
اعواد الكبريت:ليس دليلاً أو أنه فارغ.هكذا، (^F)
وحده سيدرج أيضًا الملفات العادية، على سبيل المثال.وهكذا كما هو موضح في zshexp
صفحة الرجل، ونحن بحاجة أيضا إلى (/)
مؤهل glob، الذي يسرد الدلائل فقط:
$ mkdir X Y Z
$ touch X/f Y/.f # directories X and Y now not empty
$ for i in *(/^F) ; do echo $i ; done
Z
وبالتالي، للتحقق مما إذا كان الدليل المحدد فارغًا، يمكنك بالتالي تشغيل:
$ mkdir X
$ for i in X(/^F) ; do echo $i ; done ; echo "finished"
X
finished
وللتأكد فقط من عدم التقاط دليل غير فارغ:
$ mkdir Y
$ touch Y/.f
$ for i in Y(/^F) ; do echo $i ; done ; echo "finished"
zsh: no matches found: Y(/^F)
finished
أُووبس!منذ Y
ليست فارغة، ولم يجد zsh أي تطابقات لها (/^F)
("الدلائل الفارغة") وبالتالي تظهر رسالة خطأ تفيد بأنه لم يتم العثور على أي تطابقات للكرة الأرضية.لذلك نحتاج إلى منع رسائل الخطأ المحتملة هذه باستخدام ملف (N)
تصفيات الكرة الأرضية:
$ mkdir Y
$ touch Y/.f
$ for i in Y(N/^F) ; do echo $i ; done ; echo "finished"
finished
وبالتالي، بالنسبة للأدلة غير الفارغة، نحتاج إلى المؤهل (N/^F)
, ، والتي يمكنك قراءتها على النحو التالي:"لا تحذرني من حالات الفشل، فالدلائل غير ممتلئة".
وبالمثل، بالنسبة للأدلة الفارغة، نحتاج إلى المؤهل (NF)
, ، والتي يمكننا قراءتها أيضًا على النحو التالي:"لا تحذرني من حالات الفشل، الأدلة الكاملة".
if ls /some/dir/* >/dev/null 2>&1 ; then echo "huzzah"; fi;
لم أر حتى الآن إجابة تستخدم grep والتي أعتقد أنها ستعطي إجابة أبسط (مع عدم وجود الكثير من الرموز الغريبة!).فيما يلي كيف أتحقق مما إذا كانت أي ملفات موجودة في الدليل باستخدام Bourne Shell:
يؤدي هذا إلى إرجاع عدد الملفات في الدليل:
ls -l <directory> | egrep -c "^-"
يمكنك ملء مسار الدليل حيث يتم كتابة الدليل.يضمن النصف الأول من الأنبوب أن الحرف الأول للإخراج هو "-" لكل ملف.ثم يحسب Egrep عدد الخط الذي يبدأ بهذا الرمز باستخدام التعبيرات العادية.الآن كل ما عليك فعله هو تخزين الرقم الذي حصلت عليه ومقارنته باستخدام علامات الاقتباس الخلفية مثل:
#!/bin/sh
fileNum=`ls -l <directory> | egrep -c "^-"`
if [ $fileNum == x ]
then
#do what you want to do
fi
x هو متغير من اختيارك.
يجب أن أقوم بالخلط بين الأشياء المقشورة والإجابات الأخيرة
find "$some_dir" -prune -empty -type d | read && echo empty || echo "not empty"
يعمل مع المسارات ذات المسافات أيضًا
إجابة بسيطة مع سحق:
if [[ $(ls /some/dir/) ]]; then echo "huzzah"; fi;
سأذهب ل find
:
if [ -z "$(find $dir -maxdepth 1 -type f)" ]; then
echo "$dir has NO files"
else
echo "$dir has files"
يؤدي هذا إلى التحقق من نتائج البحث عن الملفات الموجودة في الدليل فقط، دون المرور عبر الدلائل الفرعية.ثم يقوم بفحص الإخراج باستخدام -z
الخيار مأخوذ من man test
:
-z STRING
the length of STRING is zero
انظر بعض النتائج:
$ mkdir aaa
$ dir="aaa"
دير فارغ:
$ [ -z "$(find aaa/ -maxdepth 1 -type f)" ] && echo "empty"
empty
فقط dirs في ذلك:
$ mkdir aaa/bbb
$ [ -z "$(find aaa/ -maxdepth 1 -type f)" ] && echo "empty"
empty
ملف في الدليل:
$ touch aaa/myfile
$ [ -z "$(find aaa/ -maxdepth 1 -type f)" ] && echo "empty"
$ rm aaa/myfile
ملف في دليل فرعي:
$ touch aaa/bbb/another_file
$ [ -z "$(find aaa/ -maxdepth 1 -type f)" ] && echo "empty"
empty
حاول باستخدام الأمر find.حدد الدليل المضمن أو كوسيطة.ثم ابدأ البحث للبحث في جميع الملفات داخل الدليل.تحقق مما إذا كانت إرجاع البحث فارغًا.صدى بيانات البحث
#!/bin/bash
_DIR="/home/user/test/"
#_DIR=$1
_FIND=$(find $_DIR -type f )
if [ -n "$_FIND" ]
then
echo -e "$_DIR contains files or subdirs with files \n\n "
echo "$_FIND"
else
echo "empty (or does not exist)"
fi
مع بعض الحلول البديلة، يمكنني العثور على طريقة بسيطة لمعرفة ما إذا كانت هناك ملفات في الدليل.يمكن أن يمتد هذا إلى المزيد باستخدام أوامر grep للتحقق على وجه التحديد من ملفات .xml أو .txt وما إلى ذلك.السابق : ls /some/dir | grep xml | wc -l | grep -w "0"
#!/bin/bash
if ([ $(ls /some/dir | wc -l | grep -w "0") ])
then
echo 'No files'
else
echo 'Found files'
fi
أنا لا أحب ls - A
الحلول المنشورة.على الأرجح أنك ترغب في اختبار ما إذا كان الدليل فارغًا لأنك لا ترغب في حذفه.ما يلي يفعل ذلك.ومع ذلك، إذا كنت ترغب فقط في تسجيل ملف فارغ، فمن المؤكد أن حذفه وإعادة إنشائه سيكون أسرع من إدراج ملفات لا حصر لها؟
هذا يجب أن يعمل...
if ! rmdir ${target}
then
echo "not empty"
else
echo "empty"
mkdir ${target}
fi
لاختبار دليل هدف محدد
if [ -d $target_dir ]; then
ls_contents=$(ls -1 $target_dir | xargs);
if [ ! -z "$ls_contents" -a "$ls_contents" != "" ]; then
echo "is not empty";
else
echo "is empty";
fi;
else
echo "directory does not exist";
fi;
يعمل بشكل جيد بالنسبة لي (عند وجود دير):
some_dir="/some/dir with whitespace & other characters/"
if find "`echo "$some_dir"`" -maxdepth 0 -empty | read v; then echo "Empty dir"; fi
مع الفحص الكامل:
if [ -d "$some_dir" ]; then
if find "`echo "$some_dir"`" -maxdepth 0 -empty | read v; then echo "Empty dir"; else "Dir is NOT empty" fi
fi