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




posix (25)

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

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

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


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

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 . ] || echo "No"

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

find . -type d -name dirname -prune -print

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

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

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

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

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

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 وما إلى ذلك ... إذا قمت بتجربتها على ملفات غير موجودة ، فسوف يخرجون بخطأ وطباعة رسالة تقول أنها غير موجودة ، وسوف يتم حجبها. تخطي. إذا قمت بتجربتها على ملفات موجودة بالفعل ، فسيتم تنفيذ الأمر وإنهاء حالة 0 ، مما يتيح لك تنفيذ ذلك.


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

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 

أجد أن الإصدار tldp.org/LDP/abs/html/testconstructs.html#DBLBRACKETS من test يجعل اختبارات الكتابة المنطقية أكثر طبيعية:

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

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

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

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

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

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

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

لاحظ أن الاختبار -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 .


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

file="foo" 
if [[ -e "$file" ]]; then echo "File Exists"; fi;

شكل أقصر:

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

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

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

اختتم هذا الجواب كبرنامج نصي 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";

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 builtin ، لكن يجب أن تكون الوسيطة الأخيرة ، حرفيًا ] ، لمطابقة الفتحة [ .

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

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

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

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


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

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

للتحقق مما إذا كان هناك دليل موجود في برنامج نصي 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

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

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 في إجابة أخرى .

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


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

(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 . في هذا المستوى ، سأفضل أن أبقيه بسيطًا - الحجج إلى الدالة هي مجرد سلاسل.


(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 ls -ld SAMPLE_DIR| grep ^d | wc -l ls -ld SAMPLE_DIR| grep ^d | wc -l -eq 1]] && echo موجود || غير موجود -ksh: not: not found [لا يوجد ملف أو دليل]


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

    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
    

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

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

    mkdir: لا يمكن إنشاء الدليل 'tempdir': الملف موجود


على افتراض أنك تريد القيام بذلك تلقائيًا من جهاز "محلي" ، دون تسجيل الدخول يدويًا إلى الجهاز "البعيد" ، يجب أن تبحث في ملحق TCL المعروف باسم Expect ، فهو مصمم خصيصًا لهذا النوع من الموقف. يبدو أن الصفحة الرئيسية أدناه تبدو كريهة ولكن لا تدع ذلك يثبطك ؛ لقد قدمت أيضًا رابطًا لبرنامج نصي لتسجيل الدخول / التفاعل عبر SSH.

http://expect.nist.gov/

http://bash.cyberciti.biz/security/expect-ssh-login-script/





shell unix posix