تحقق من وجود دليل في برنامج نصي shell


14 Answers

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

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

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

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




اكتب هذا الرمز على bash promt

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



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

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

فمثلا:

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

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

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

لمعرفة الخيارات الممكنة أو المساعدة الإضافية ، تحقق من:

  • help [
  • help test
  • man test أو man [



اختتم هذا الجواب كبرنامج نصي shell

أمثلة

$ 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";



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

$ 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 على تعبيرات Bash الشرطية و [ أمر مدمج و [[ commmand .




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

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 (وليس حلا رائعا لذوقي) ، ومع ذلك سيكون هناك خروج صفر. ربما شخص ما يمكن أن تحسن على هذا.




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

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

Explanation: الأمر "ls" يعطي خطأ "ls: / x: لا يوجد ملف أو دليل" إذا كان الدليل أو symlink غير موجود ، كما يقوم بتعيين كود الإرجاع ، والذي يمكنك استرجاعه عبر "$" ، إلى غير -كل (عادة "1"). تأكد من التحقق من رمز الإرجاع مباشرةً بعد استدعاء "ls".




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

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




هنا تعبير براغماتي للغاية:

(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 داخل subshell ( ... ) ، لا يؤثر الأمر على الدليل الحالي للمتصل. إذا كان الدليل موجودًا ، فإن هذا المستند الفرعي والدالة هما مجرد إجراء.

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

Tl؛ dr: إذا كانت السلسلة التي تم تمريرها إلى هذه الدالة فارغة ، فإننا نخرج مرة أخرى من subshell ( ... ) ونرجع من الدالة برسالة خطأ معينة.

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

${parameter:?word}

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

و

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

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

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

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




Git Bash + Dropbox + Windows:

لم تنجح أي من الحلول الأخرى في مجلد Dropbox الخاص بي ، والذي كان غريباً لأنني أستطيع أن أضغط على مسار dropbox الرمزي.

#!/bin/bash

dbox="~/Dropbox/"
result=0
prv=$(pwd) && eval "cd $dbox" && result=1 && cd "$prv"
echo $result

read -p "Press Enter To Continue:"

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

https://pastebin.com/QF2Exmpn




المزيد من الميزات باستخدام 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
    



يقوم الأمر 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



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

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 



تحقق مما إذا كان الدليل موجودًا ، فاجعله آخر

[ -d "$DIRECTORY" ] || mkdir $DIRECTORY



وفقا لتعليق :

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

mkdir -p /some/directory/you/want/to/exist || exit 1



Related