تحقق من وجود دليل في برنامج نصي Shell
سؤال
ما الأمر الذي يمكن استخدامه للتحقق من وجود الدليل أم لا، داخل برنامج نصي 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 [
برنامج نصي بسيط لاختبار ما إذا كان الدليل أو الملف موجودًا أم لا:
if [ -d /home/ram/dir ] # for file "if [-f /home/rama/file]" then echo "dir present" else echo "dir not present" fi
برنامج نصي بسيط للتحقق مما إذا كان الدليل موجودًا أم لا:
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