سؤال برمجة Bash: اختبار للدليل الفارغ


أرغب في اختبار ما إذا كان الدليل لا يحتوي على أي ملفات. إذا كان الأمر كذلك ، فسوف أتخطى بعض المعالجة.

جربت ما يلي:

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

يعطي هذا الخطأ التالي:

line 1: [: too many arguments

هل يوجد حل / بديل؟


71
2017-10-31 03:47


الأصل




الأجوبة:


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

أيضا ، سيكون من الرائع التحقق من وجود الدليل من قبل.


87
2017-10-31 03:53



لا تستخدم && و || الوقت ذاته! إذا echo "Not Empty" فشل echo "Empty" سوف يعمل! محاولة echo "test" && false || echo "fail"! نعم اعرف echo لن تفشل ، ولكن إذا غيرت أي أمر آخر ، فستكون مفاجئًا! - uzsolt
يرجى تقديم مثال واحد على الأقل عندما لا يعمل الرمز أعلاه. بشكل ملموس هذا الرمز صحيح تماما. آمل أن يتمكن السائل من تكييف هذا لأغراضه الخاصة - Andrey Atapin
[ "$(ls -A /)" ] && touch /non-empty || echo "Empty" - إذا كنت تريد "وضع علامة" على dirs غير فارغ مع ملف تم إنشاؤه باسم non-empty، وسوف يفشل ويطبع "فارغة". - uzsolt
اين touch /empty في خطي؟ - Andrey Atapin
أوه لا! هناك مشكلة مهمة جدًا في هذا الرمز. يجب أن يكون if [ -n "$(ls -A /path/to/dir)" ]; then ... يرجى تحديث الإجابة قبل أن يلصق شخص ما هذه الشفرة في خادمه في مكان ما ويكتشف المخترق كيفية استغلالها. إذا /path/to/dir ليس فارغا ، ثم تمرير أسماء الملفات هناك كوسائط ل /bin/test الذي من الواضح أنه ليس المقصود. مجرد إضافة -n حجة ، حل المشكلة. شكر! - Edward Ned Harvey


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

16
2017-10-31 10:53



صحيح وسريع. لطيف! - l0b0
يحتاج إلى اقتباسات (2x) والاختبار -n أن تكون صحيحة وآمنة (اختبار مع دليل بمسافات في الاسم ، واختبارها مع دليل غير فارغ مع الاسم '0 = 1'). ... [ -n "$(find "$DIR_TO_CHECK" -maxdepth 0 -type d -empty 2>/dev/null)" ]; ... - Zrin
ivan_pozdeev هذا ليس صحيحًا ، على الأقل بالنسبة لإيجاد غنو. قد تفكر grep. serverfault.com/questions/225798/... - Vladimir Panteleev
قد يكون من الأسهل الكتابة find "$DIR_TO_CHECK" -maxdepth 0 -type d -empty | grep .، والاعتماد على حالة الخروج من grep. أياً كانت الطريقة التي تقوم بها ، فهذه هي الإجابة الصحيحة على هذا السؤال. - Tom Anderson


لا حاجة لحساب أي شيء أو قشور. تستطيع ايضا استخذام read بالاشتراك مع find. إذا findخرج فارغة ، ستعود false:

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

هذا يجب أن يكون محمولا.


12
2017-10-29 21:07



حل لطيف ، ولكن أعتقد أن لديك echo المكالمات تعكس النتيجة الخاطئة: في الاختبار الخاص بي (تحت Cygwin) find . -mindepth 1 | read كان رمز الخطأ 141 في دير غير فارغ ، و 0 في دير فارغ - Lucas Cimon
LucasCimon ليس هنا (macOS و GNU / Linux). للحصول على دليل غير فارغ ، read ترجع 0 ، ولخلاصة واحدة ، 1. - slhck


#!/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

9
2017-11-01 14:51



يجب أن يكون ذلك ، لا حاجة إلى تحليل إصدار ls ، فقط انظر ما إذا كان فارغًا أم لا. استخدام البحث فقط يشعر وكأنه مبالغة بالنسبة لي. - akostadinov


هذا سوف يقوم بالمهمة في دليل العمل الحالي (.):

[ `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)


4
2017-10-31 10:06



استعمال ls -A في حين أن. بعض أنظمة الملفات لا تملك . و .. روابط رمزية وفقًا للمستندات. - Daniel Beck♦
شكراDaniel ، قمت بتحرير جوابي بعد اقتراحك. أعلم أنه قد تتم إزالة "1" أيضًا. - ztank1013
لا يضر ، ولكن هذا يعني إذا لم يكن الإخراج إلى محطة. نظرًا لأنك تقوم بتوصيله إلى برنامج آخر ، فستكون متكررة. - Daniel Beck♦
-1 هو بالتأكيد زائدة عن الحاجة. حتى و إن ls لن تطبع عنصرًا واحدًا في كل سطر عندما يتم توجيهه إلى أنبوبة ، ثم لا يؤثر على فكرة التحقق مما إذا كان ينتج خطوطًا صفرًا أو أكثر. - Victor Yarema


استخدم ما يلي:

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

بهذه الطريقة ، أنت مستقل عن تنسيق إخراج ls. -mindepth يتخطى الدليل نفسه ، -maxdepth يمنع الدفاع بشكل متكرر في الدلائل الفرعية لتسريع الأمور.


3
2017-10-31 10:17



بالطبع ، أنت تعتمد الآن على wc -l و find تنسيق الإخراج (الذي هو عادي معقول على الرغم من). - Daniel Beck♦


باستخدام صفيف:

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

3
2017-08-12 21:46



حل لطيف جدا ، ولكن لاحظ أنه يتطلب shopt -s nullglob - xebeche
ال ${#files[@]} == 2 لا يقف الافتراض للجذر الرئيسي (قد لا تختبره إذا كان فارغًا ، لكن قد لا يحتوي بعض التعليمات البرمجية التي لا تعرف هذا القيد). - ivan_pozdeev


طريقة سهلة الاستخدام ، ولكن بطريقة bash فقط ، بدون تكلفة:

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

هذا يستفيد من حقيقة ذلك test يخرج مدمج مع 2 إذا أعطيت أكثر من حجة واحدة بعد -e: أول، "$1"/* يتم توسيع glob بواسطة bash. ينتج عن هذا وسيطة واحدة لكل ملف. وبالتالي

  • إذا لم تكن هناك ملفات ، فإن العلامة النجمية في test -e "$1"* لا توسيع ، لذلك شل يعود إلى محاولة ملف اسمه *، والتي ترجع 1.

  • ... إلا إذا كان هناك بالفعل ملف واحد اسمه بالضبط *ثم تتوسع العلامة النجمية إلى جانب العلامة النجمية التي تنتهي بنفس الكلمة التي يطلق عليها أعلاه ، أي. test -e "dir/*"، فقط هذه المرة تقوم بارجاع 0. (شكراTrueY للإشارة إلى ذلك.)

  • إذا كان هناك ملف واحد ، test -e "dir/file" يتم تشغيل ، والتي ترجع 0.

  • ولكن إذا كان هناك ملفات أكثر من 1 ، test -e "dir/file1" "dir/file2" يتم تشغيلها ، والتي تعمل على الإبلاغ عنها كخطأ في الاستخدام ، بمعنى 2.

case يلف المنطق بالكامل بحيث يتم الإبلاغ عن الحالة الأولى فقط ، مع حالة خروج واحدة على أنها نجاح.

مشاكل محتملة لم أتحقق منها:

  • هناك ملفات أكثر من عدد من الحجج المسموح بها - أعتقد أن هذا ممكن تتصرف مماثلة لحالة مع ملفات 2+.

  • أو هناك ملف بالفعل يحمل اسمًا فارغًا - لست متأكدًا من إمكانية وجوده في أي ملف عاقل OS / FS.


3
2017-10-24 01:23



تصحيح طفيف: إذا لم يكن هناك ملف في dir / ، إذن test -e dir/* يسمى. إذا كان الملف الوحيد هو '*' في dir ثم سيقوم الاختبار بإرجاع 0. إذا كان هناك المزيد من الملفات ، فإنه يقوم بإرجاع 2. لذلك يعمل كما هو موضح. - TrueY
أنت على حق ،TrueY ، لقد أدرجتها في الإجابة. شكر! - Alois Mahdal


أعتقد أن الحل الأفضل هو:

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
2017-10-29 20:57