سؤال

ما الأمر الذي يمكن استخدامه للتحقق من وجود الدليل أم لا، داخل برنامج نصي Shell؟

هل كانت مفيدة؟

المحلول

للتحقق من وجود دليل في برنامج شل النصي، يمكنك استخدام ما يلي:

if [ -d "$DIRECTORY" ]; then
  # Control will enter here if $DIRECTORY exists.
fi

أو للتحقق من عدم وجود الدليل:

if [ ! -d "$DIRECTORY" ]; then
  # Control will enter here if $DIRECTORY doesn't exist.
fi

ولكن كما جون اريكسون كما يشير، قد لا تعمل الأوامر اللاحقة على النحو المنشود إذا لم تأخذ في الاعتبار أن الرابط الرمزي للدليل سوف يجتاز هذا الاختبار أيضًا.على سبيل المثالتشغيل هذا:

ln -s "$ACTUAL_DIR" "$SYMLINK"
if [ -d "$SYMLINK" ]; then 
  rmdir "$SYMLINK" 
fi

سوف تنتج رسالة الخطأ:

rmdir: failed to remove `symlink': Not a directory

لذلك قد يتعين التعامل مع الروابط الرمزية بشكل مختلف، إذا كانت الأوامر اللاحقة تتوقع أدلة:

if [ -d "$LINK_OR_DIR" ]; then 
  if [ -L "$LINK_OR_DIR" ]; then
    # It is a symlink!
    # Symbolic link specific commands go here.
    rm "$LINK_OR_DIR"
  else
    # It's a directory!
    # Directory command goes here.
    rmdir "$LINK_OR_DIR"
  fi
fi

خذ ملاحظة خاصة بعلامات الاقتباس المزدوجة المستخدمة لتغليف المتغيرات، والسبب في ذلك موضح بواسطة 8jean في إجابة أخرى.

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

نصائح أخرى

تذكر دائمًا أن تلتف المتغيرات في عروض أسعار مزدوجة عند الرجوع إليها في نص Bash.يكبر الأطفال هذه الأيام مع فكرة أنه يمكن أن يكون لديهم مسافات والكثير من الشخصيات المضحكة الأخرى في أسماء الدليل الخاصة بهم.(المساحات!في أيامي، لم يكن لدينا مساحات فاخرة!;))

في أحد الأيام، سيقوم أحد هؤلاء الأطفال بتشغيل السيناريو الخاص بك معه $DIRECTORY ضبط ل "My M0viez" وسوف ينفجر البرنامج النصي الخاص بك.أنت لا تريد ذلك.لذا استخدم هذا.

if [ -d "$DIRECTORY" ]; then
    # Will enter here if $DIRECTORY exists, even if it contains spaces
fi

لاحظ ال يمكن أن يؤدي الاختبار إلى بعض النتائج المدهشة:

$ ln -s tmp/ t
$ if [ -d t ]; then rmdir t; fi
rmdir: directory "t": Path component not a directory

الملف تحت:"متى لا يكون الدليل دليلًا؟" الاجابة:"عندما يكون ارتباطا مع الدليل." اختبار أكثر شمولية قليلاً:

if [ -d t ]; then 
   if [ -L t ]; then 
      rm t
   else 
      rmdir t
   fi
fi

يمكنك العثور على مزيد من المعلومات في دليل Bash على باش التعبيرات الشرطية و ال [ أمر مدمج و ال [[ أمر مركب.

أجد قوس مزدوج نسخة من test يجعل كتابة اختبارات المنطق أكثر طبيعية:

if [[ -d "${DIRECTORY}" && ! -L "${DIRECTORY}" ]] ; then
    echo "It's a bona-fide directory"
fi

شكل أقصر:

[ -d "$DIR" ] && echo "Yes"

للتحقق من وجود دليل، يمكنك استخدام بنية if بسيطة مثل هذا:

if [ -d directory/path to a directory ] ; then
#Things to do

else #if needed #also: elif [new condition] 
# things to do
fi

يمكنك أن تفعل ذلك أيضًا بشكل سلبي

if [ ! -d directory/path to a directory ] ; then
# things to do when not an existing directory

ملحوظة:كن حذرًا، اترك مساحات فارغة على جانبي قوسي الفتح والإغلاق.

بنفس بناء الجملة يمكنك استخدام:

-e: any kind of archive 

-f: file 

-h: symbolic link 

-r: readable file 

-w: writable file 

-x: executable file 

-s: file size greater than zero 
if [ -d "$DIRECTORY" ]; then  
    # Here if $DIRECTORY exists  
fi

يمكنك استخدام test -d (يرى man test).

-d file صحيح إذا كان الملف موجودًا وهو دليل.

على سبيل المثال:

test -d "/etc" && echo Exists || echo Does not exist

ملحوظة:ال test الأمر هو نفس التعبير الشرطي [ (يرى: man [)، لذا فهو قابل للنقل عبر نصوص shell النصية.

[ - وهذا مرادف لل test مدمج، ولكن يجب أن تكون الوسيطة الأخيرة حرفية ], ، لتتناسب مع الافتتاح [.

للحصول على الخيارات الممكنة أو مزيد من المساعدة، تحقق من:

  • help [
  • help test
  • man test أو man [
  1. برنامج نصي بسيط لاختبار ما إذا كان الدليل أو الملف موجودًا أم لا:

    if [ -d /home/ram/dir ]   # for file "if [-f /home/rama/file]" 
    then 
        echo "dir present"
    else
        echo "dir not present"
    fi
    
  2. برنامج نصي بسيط للتحقق مما إذا كان الدليل موجودًا أم لا:

    mkdir tempdir   # if you want to check file use touch instead of mkdir
    ret=$?
    if [ "$ret" == "0" ]
    then
        echo "dir present"
    else
        echo "dir not present"
    fi
    

    ستتحقق البرامج النصية أعلاه من وجود الدير أم لا

    $? إذا نجح الأمر الأخير فإنه يُرجع "0" قيمة أخرى ليست صفرية.يفترض tempdir موجود بالفعل بعد ذلك mkdir tempdir سوف يعطي خطأ مثل أدناه:

    مكدير:لا يمكن إنشاء الدليل "tempdir":الملف موجود

أو لشيء عديم الفائدة تمامًا:

[ -d . ] || echo "No"

إليك لغة عملية للغاية:

(cd $dir) || return # is this a directory,
                    # and do we have access?

عادةً ما أقوم بتغليفها في وظيفة:

can_use_as_dir() { 
    (cd ${1:?pathname expected}) || return
}

أو:

assert_dir_access() { 
    (cd ${1:?pathname expected}) || exit
}

والشيء الجميل في هذا النهج هو أنني لا أحتاج إلى التفكير في رسالة خطأ جيدة.

cd سوف يعطيني رسالة قياسية من سطر واحد إلى stderr بالفعل.وسيقدم أيضًا معلومات أكثر مما سأتمكن من تقديمه.من خلال أداء cd داخل قذيفة فرعية ( ... ), ، لا يؤثر الأمر على الدليل الحالي للمتصل.إذا كان الدليل موجودًا، فإن هذا الغلاف الفرعي والدالة يعدان مجرد عملية محظورة.

التالي هو الحجة التي ننتقل إليها cd: ${1:?pathname expected}.يعد هذا شكلاً أكثر تفصيلاً لاستبدال المعلمات والذي سيتم شرحه بمزيد من التفصيل أدناه.

تل ؛دكتور:إذا كانت السلسلة التي تم تمريرها إلى هذه الوظيفة فارغة، فإننا نخرج مرة أخرى من القشرة الفرعية ( ... ) والعودة من الوظيفة مع رسالة الخطأ المحددة.


نقلا عن ksh93 صفحة الرجل:

${parameter:?word}

لو parameter تم تعيينه وهو غير فارغ ثم استبدل قيمته؛خلاف ذلك، طباعة word والخروج من الصدفة (إن لم تكن تفاعلية).لو word تم حذفه ثم تتم طباعة رسالة قياسية.

و

إذا كان القولون : تم حذفه من التعبيرات المذكورة أعلاه ، ثم تتحقق shell فقط ما إذا كانت المعلمة قد تم تعيينها أم لا.

الصياغة هنا خاصة بوثائق الصدفة، مثل word قد تشير إلى أي سلسلة معقولة ، بما في ذلك المسافة البيضاء.

في هذه الحالة بالذات، أعلم أن رسالة الخطأ القياسية 1: parameter not set ليست كافية، لذلك أقوم بتكبير نوع القيمة التي نتوقعها هنا - pathname من الدليل.

ملاحظة فلسفية:الصدفة ليست لغة موجهة للكائنات، هكذا تقول الرسالة pathname, ، لا directory.في هذا المستوى، أفضل أن أبقي الأمر بسيطًا - وسيطات الدالة هي مجرد سلاسل.

if [ -d "$Directory" -a -w "$Directory" ]
then
    #Statements
fi

يتحقق الكود أعلاه من وجود الدليل وما إذا كان قابلاً للكتابة.

اكتب هذا الرمز في bash promt

if [ -d "$DIRECTORY" ]; then
  # if true this block of code will execute
fi

المزيد من الميزات باستخدام find

  • التحقق من وجود المجلد ضمن الدلائل الفرعية:

    found=`find -type d -name "myDirectory"`
    if [ -n "$found"]
    then
        # The variable 'found' contains the full path where "myDirectory" is.
        # It may contain several lines if there are several folders named "myDirectory".
    fi
    
  • تحقق من وجود مجلد واحد أو عدة مجلدات بناءً على نمط داخل الدليل الحالي:

    found=`find -maxdepth 1 -type d -name "my*"`
    if [ -n "$found"]
    then
        # The variable 'found' contains the full path where folders "my*" have been found.
    fi
    
  • كلا المجموعتين.في المثال التالي، يتم التحقق من وجود المجلد في الدليل الحالي:

    found=`find -maxdepth 1 -type d -name "myDirectory"`
    if [ -n "$found"]
    then
        # The variable 'found' is not empty => "myDirectory"` exists.
    fi
    

في الواقع، يجب عليك استخدام عدة أدوات للحصول على نهج مضاد للرصاص:

DIR_PATH=`readlink -f "${the_stuff_you_test}"` # Get rid of symlinks and get abs path
if [[ -d "${DIR_PATH}" ]] ; Then # now you're testing
    echo "It's a dir";
fi

لا داعي للقلق بشأن المسافات والأحرف الخاصة طالما أنك تستخدمها "${}".

لاحظ أن [[]] ليست محمولة كما [], ، ولكن نظرًا لأن معظم الأشخاص يعملون مع الإصدارات الحديثة من Bash (نظرًا لأن معظم الأشخاص لا يعملون حتى مع سطر الأوامر :-p)، فإن الفائدة أكبر من المتاعب.

للتحقق من أكثر من دليل استخدم هذا الرمز:

if [ -d "$DIRECTORY1" ] && [ -d "$DIRECTORY2" ] then
    # Things to do
fi

هل فكرت في القيام بكل ما تريد القيام به في if بدلا من النظر قبل أن تقفز؟

على سبيل المثال، إذا كنت تريد التحقق من وجود دليل قبل إدخاله، فحاول القيام بذلك:

if pushd /path/you/want/to/enter; then
    # commands you want to run in this directory
    popd
fi

إذا كان المسار الذي تعطيه ل pushd موجود، ستدخل إليه وستخرج به 0, ، والتي تعني then سيتم تنفيذ جزء من البيان.إذا لم يكن موجودًا، فلن يحدث شيء (بخلاف بعض المخرجات التي تشير إلى أن الدليل غير موجود، وهو ما قد يكون أثرًا جانبيًا مفيدًا على أي حال لتصحيح الأخطاء).

يبدو أفضل من هذا، الأمر الذي يتطلب تكرار نفسك:

if [ -d /path/you/want/to/enter ]; then
    pushd /path/you/want/to/enter
    # commands you want to run in this directory
    popd
fi

نفس الشيء يعمل مع cd, mv, rm, ، إلخ...إذا قمت بتجربتها على ملفات غير موجودة، فسوف تخرج مع وجود خطأ وتطبع رسالة تفيد بأنها غير موجودة، وسيختفي جهازك then سيتم تخطي الكتلة.إذا قمت بتجربتها على ملفات موجودة بالفعل، فسيتم تنفيذ الأمر والخروج بحالة 0, ، السماح الخاص بك then كتلة للتنفيذ.

تحقق من وجود الدليل، وإلا قم بإنشاء واحد

[ -d "$DIRECTORY" ] || mkdir $DIRECTORY
[[ -d "$DIR" && ! -L "$DIR" ]] && echo "It's a directory and not a symbolic link"

ملحوظة:يعتبر اقتباس المتغيرات ممارسة جيدة.

[ -d ~/Desktop/TEMPORAL/ ] && echo "DIRECTORY EXISTS" || echo "DIRECTORY DOES NOT EXIST"

هذه الإجابة ملفوفة كبرنامج نصي شل

أمثلة

$ is_dir ~                           
YES

$ is_dir /tmp                        
YES

$ is_dir ~/bin                       
YES

$ mkdir '/tmp/test me'

$ is_dir '/tmp/test me'
YES

$ is_dir /asdf/asdf                  
NO

# Example of calling it in another script
DIR=~/mydata
if [ $(is_dir $DIR) == "NO" ]
then
  echo "Folder doesnt exist: $DIR";
  exit;
fi

is_dir

function show_help()
{
  IT=$(CAT <<EOF

  usage: DIR
  output: YES or NO, depending on whether or not the directory exists.

  )
  echo "$IT"
  exit
}

if [ "$1" == "help" ]
then
  show_help
fi
if [ -z "$1" ]
then
  show_help
fi

DIR=$1
if [ -d $DIR ]; then 
   echo "YES";
   exit;
fi
echo "NO";

باستخدام -e سوف يتحقق الاختيار من الملفات وهذا يشمل الدلائل.

if [ -e ${FILE_PATH_AND_NAME} ]
then
    echo "The file or directory exists."
fi

حسب جوناثان تعليق:

إذا كنت ترغب في إنشاء الدليل وهو غير موجود بعد، فإن أبسط تقنية هي استخدامه mkdir -p الذي ينشئ الدليل - وأي أدلة مفقودة في المسار - ولا يفشل إذا كان الدليل موجودًا بالفعل، لذا يمكنك القيام بذلك كله مرة واحدة باستخدام:

mkdir -p /some/directory/you/want/to/exist || exit 1
if [ -d "$DIRECTORY" ]; then
    # Will enter here if $DIRECTORY exists
fi

هذا ليس صحيحا تماما...إذا كنت تريد الانتقال إلى هذا الدليل، فستحتاج أيضًا إلى الحصول على حقوق التنفيذ على الدليل.ربما تحتاج إلى الحصول على حقوق الكتابة أيضًا.

ولذلك:

if [ -d "$DIRECTORY" ] && [ -x "$DIRECTORY" ] ; then
    # ... to go to that directory (even if DIRECTORY is a link)
    cd $DIRECTORY
    pwd
fi

if [ -d "$DIRECTORY" ] && [ -w "$DIRECTORY" ] ; then
    # ... to go to that directory and write something there (even if DIRECTORY is a link)
    cd $DIRECTORY
    touch foobar
fi

ال ls الأمر بالتزامن مع -l (القائمة الطويلة) يقوم الخيار بإرجاع معلومات السمات حول الملفات والأدلة.
وعلى وجه الخصوص الحرف الأول من ls -l الإخراج عادة ما يكون أ d أو أ - (اندفاع).في حالة أ d المدرج هو دليل بالتأكيد.

سيخبرك الأمر التالي في سطر واحد فقط إذا كان الأمر المحدد ISDIR يحتوي المتغير على مسار إلى دليل أم لا:

[[ $(ls -ld "$ISDIR" | cut -c1) == 'd' ]] &&
    echo "YES, $ISDIR is a directory." || 
    echo "Sorry, $ISDIR is not a directory"

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

    [claudio@nowhere ~]$ ISDIR="$HOME/Music" 
    [claudio@nowhere ~]$ ls -ld "$ISDIR"
    drwxr-xr-x. 2 claudio claudio 4096 Aug 23 00:02 /home/claudio/Music
    [claudio@nowhere ~]$ [[ $(ls -ld "$ISDIR" | cut -c1) == 'd' ]] && 
        echo "YES, $ISDIR is a directory." ||
        echo "Sorry, $ISDIR is not a directory"
    YES, /home/claudio/Music is a directory.

    [claudio@nowhere ~]$ touch "empty file.txt"
    [claudio@nowhere ~]$ ISDIR="$HOME/empty file.txt" 
    [claudio@nowhere ~]$ [[ $(ls -ld "$ISDIR" | cut -c1) == 'd' ]] && 
        echo "YES, $ISDIR is a directory." || 
        echo "Sorry, $ISDIR is not a directoy"
    Sorry, /home/claudio/empty file.txt is not a directory
file="foo" 
if [[ -e "$file" ]]; then echo "File Exists"; fi;

إذا كنت تريد التحقق من وجود دليل، بغض النظر عما إذا كان دليلاً حقيقيًا أو رابطًا رمزيًا، فاستخدم هذا:

ls $DIR
if [ $? != 0 ]; then
        echo "Directory $DIR already exists!"
        exit 1;
fi
echo "Directory $DIR does not exist..."

توضيح:يعطي الأمر "ls" خطأ "ls:/س:لا يوجد مثل هذا الملف أو الدليل" في حالة عدم وجود الدليل أو الارتباط الرمزي، كما يقوم أيضًا بتعيين رمز الإرجاع، الذي يمكنك استرداده عبر "$؟"، إلى قيمة غير فارغة (عادةً "1").تأكد من التحقق من رمز الإرجاع مباشرة بعد الاتصال بـ "ls".

(1)

[ -d Piyush_Drv1 ] && echo ""Exists"" || echo "Not Exists"

(2)

[ `find . -type d -name Piyush_Drv1 -print | wc -l` -eq 1 ] && echo Exists || echo "Not Exists"

(3)

[[ -d run_dir  && ! -L run_dir ]] && echo Exists || echo "Not Exists"

إذا وجدت مشكلة مع أحد الأساليب المذكورة أعلاه.

مع ls يأمر؛الحالات التي لا يكون فيها الدليل موجودًا - تظهر رسالة خطأ

$ [[ ls -ld SAMPLE_DIR| grep ^d | wc -l -eq 1]] && echo موجود || لا يوجد -ksh:لا:لم يتم العثور على [لا يوجد مثل هذا الملف أو الدليل]

توجد حلول رائعة، ولكن في النهاية سيفشل كل برنامج نصي إذا لم تكن في الدليل الصحيح.لذلك رمز مثل هذا:

if [ -d "$LINK_OR_DIR" ]; then 
if [ -L "$LINK_OR_DIR" ]; then
    # It is a symlink!
    # Symbolic link specific commands go here
    rm "$LINK_OR_DIR"
else
    # It's a directory!
    # Directory command goes here
    rmdir "$LINK_OR_DIR"
fi
fi

سيتم تنفيذه بنجاح فقط إذا كنت في لحظة التنفيذ في دليل يحتوي على دليل فرعي تقوم بالتحقق منه.

أفهم السؤال الأولي مثل هذا:للتحقق من وجود الدليل بغض النظر عن موقع المستخدم في نظام الملفات.لذا فإن استخدام الأمر "find" قد يؤدي إلى الحيلة:

dir=" "
echo "Input directory name to search for:"
read dir
find $HOME -name $dir -type d

يعد هذا الحل جيدًا لأنه يسمح باستخدام أحرف البدل، وهي ميزة مفيدة عند البحث عن الملفات/الأدلة.المشكلة الوحيدة هي أنه في حالة عدم وجود الدليل الذي تم البحث عنه، فإن الأمر "find" لن يطبع أي شيء إلى stdout (ليس حلاً أنيقًا لذوقي) وسيكون له مع ذلك مخرج صفر.ربما يمكن لشخص ما تحسين هذا.

تجد أدناه يمكن استخدامها،

find . -type d -name dirname -prune -print
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top