Яку команду можна використовувати для перевірки існування каталогу чи ні в сценарії оболонки Bash?
Яку команду можна використовувати для перевірки існування каталогу чи ні в сценарії оболонки Bash?
Відповіді:
Щоб перевірити, чи існує каталог у скрипті оболонки, ви можете скористатися наступним:
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 пояснює в іншій відповіді .
Якщо змінні містять пробіли чи інші незвичайні символи, це, ймовірно, спричинить збій сценарію.
[ ! -d "$DIRECTORY" ]
це буде істинним, або якщо $DIRECTORY
його немає, або якщо він існує, але не є каталогом. Розгляньте щось на кшталт if [ ! -d "$DIRECTORY" ] ; then mkdir "$DIRECTORY" ; fi
; це не вдасться, якщо "$DIRECTORY"
є файл. (Звичайно, ви повинні перевірити, чи mkdir
вдалося це все-таки; є кілька причин, через які це може відбутися.)
-d
), так і для символьної посилання ( -L
), простіше просто додати косу рису до змінної, наприклад if [ -d "${THING:+$THING/}" ]
. Довідник не заперечує додатковий нахил. Файл оцінюється як хибний. Порожній залишиться порожнім, таким неправдивим. І символьне посилання буде вирішено до місця призначення. Звичайно, це залежить від вашої мети. Якщо ви хочете туди поїхати , це добре. Якщо ви хочете її видалити , то код у цій відповіді краще.
Не забудьте завжди загортати змінні у подвійні лапки, посилаючись на них у сценарії Bash. Діти в ці дні виростають з думкою, що вони можуть мати пробіли та безліч інших смішних символів у своїх іменах каталогу. (Пробіли! Ще в мої часи у нас не було фантазійних просторів!;))
Одного разу один із цих дітей запустить ваш сценарій із $DIRECTORY
встановленим на, "My M0viez"
і ваш сценарій підірветься. Ти цього не хочеш. Тому використовуйте це.
if [ -d "$DIRECTORY" ]; then
# Will enter here if $DIRECTORY exists, even if it contains spaces
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 та [
вбудованої команди та [[
складних команд .
if [ -d tmpdir -a ! -L tmpdir ]; then echo "is directory"; rmdir tmpdir; fi
... або, для однієї команди, яка працює на обох посиланнях і режимах:rm -r tmpdir
Я вважаю, що версія з подвійною дужкоюtest
робить логічні тести написання більш природними:
if [[ -d "${DIRECTORY}" && ! -L "${DIRECTORY}" ]] ; then
echo "It's a bona-fide directory"
fi
if [[ -d "$TARFILE" ]]
я отримую [[: не знайдено
[[ ]]
підтримується, але насправді не забезпечує жодної іншої функціональності [ ]
. Якщо портативність викликає занепокоєння, дотримуйтесь [ ]
та використовуйте необхідні способи вирішення.
Коротша форма:
[ -d "$DIR" ] && echo "Yes"
if $dir is a dir, then echo "yes"
:? Трохи пояснень допоможе :)
cmd && other
це загальна стенограма для if cmd; then other; fi
- це працює з більшістю мов програмування, які підтримують булеву логіку, і називається оцінкою короткого замикання .
set -e
(що є найкращою практикою програмування оболонок ).
[ -d "$DIR" ]
перевіряється (слідує за ним && echo Yes
), тому я вважаю, що set -e
це не має значення для поведінки сценарію (тобто, якщо тест не вдався, сценарій продовжується нормально).
Щоб перевірити, чи існує каталог, ви можете скористатися такою простою 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 /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
з’явиться помилка, як показано нижче:
mkdir: не вдається створити каталог 'tempdir': файл існує
Можна використовувати test -d
(див. man test
).
-d file
Щоправда, якщо файл існує і це каталог.
Наприклад:
test -d "/etc" && echo Exists || echo Does not exist
Примітка. test
Команда така ж, як і умовне вираження [
(див. man [
:), Тому вона є портативною через сценарії оболонки.
[
- Це синонімtest
вбудованого, але останній аргумент повинен бути буквальним]
, щоб відповідати відкриттю[
.
Для можливих варіантів або додаткової допомоги перевірте:
help [
help test
man test
або man [
Або для чогось абсолютно марного:
[ -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
дасть мені стандартне одно рядкове повідомлення до стандартної помилки . Це також дасть більше інформації, ніж я можу надати. Виконуючи cd
всередині підзаголовка ( ... )
, команда не впливає на поточний каталог абонента. Якщо каталог існує, ця доподібна оболонка та функція є просто неопераційними.
Далі йде аргумент , що ми переходимо до cd
: ${1:?pathname expected}
. Це більш детальна форма заміни параметрів, яка більш докладно пояснюється нижче.
Tl; dr: Якщо рядок, переданий цій функції, порожній, ми знову виходимо з нижньої частини ( ... )
і повертаємось із функції із поданим повідомленням про помилку.
Цитування зі ksh93
сторінки man:
${parameter:?word}
Якщо
parameter
встановлено і є недійсним, то замініть його значення; в іншому випадку - друкword
та вихід із оболонки (якщо не інтерактивна). Якщоword
пропущено, тоді друкується стандартне повідомлення.
і
Якщо двокрапка
:
пропущена із наведених вище виразів, тоді оболонка перевіряє, встановлений чи ні параметр.
Фразування тут властиве документації оболонки, оскільки word
може посилатися на будь-який розумний рядок, включаючи пробіл.
У цьому конкретному випадку я знаю, що стандартне повідомлення про помилку 1: parameter not set
недостатньо, тому я збільшую тип значення, яке ми очікуємо тут - pathname
каталог.
Філософська примітка:
Оболонка не є об'єктно-орієнтованою мовою, тому повідомлення говорить pathname
, що ні directory
. На цьому рівні я вважаю за краще просто - аргументи функції є лише рядками.
test -d
як пояснив @Grundlefleck.
test -d /unreadable/exists
не вдасться, навіть якщо аргумент існує.
if [ -d "$Directory" -a -w "$Directory" ]
then
#Statements
fi
Вищевказаний код перевіряє, чи існує каталог і чи він піддається запису.
DIRECTORY=/tmp
if [ -d "$DIRECTORY" ]; then
echo "Exists"
fi
space
після [
-> [`` -d . Я отримав помилку через відсутність місця
Введіть цей код у запиті Bash:
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
find -maxdepth 1 -type d -name 'pattern'
. Ви не заперечуєте, якщо я додаю у вашій відповіді цю хитрість? Ура;)
Насправді вам слід скористатися кількома інструментами, щоб отримати бронезахисний підхід:
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
а не дивитися, перш ніж стрибати?
Тобто, якщо ви хочете перевірити наявність каталогу перед тим, як ввести його, спробуйте просто зробити це:
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
блоку виконуватись.
Щоб перевірити більше одного каталогу, використовуйте цей код:
if [ -d "$DIRECTORY1" ] && [ -d "$DIRECTORY2" ] then
# Things to do
fi
Перевірте, чи існує каталог, інакше зробіть:
[ -d "$DIRECTORY" ] || mkdir $DIRECTORY
mkdir -p "$DIRECTORY"
для того ж ефекту.
[[ -d "$DIR" && ! -L "$DIR" ]] && echo "It's a directory and not a symbolic link"
Примітка: Цитування змінних є хорошою практикою.
Пояснення:
-d
: перевірте, чи це каталог-L
: перевірити, чи це символічне посилання[ -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
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
Використовуйте file
програму. Враховуючи, що всі каталоги також є файлами в Linux, вистачить наступної команди:
file $directory_name
Перевірка неіснуючого файлу: file blah
Вихід: cannot open 'blah' (No such file or directory)
Перевірка наявного каталогу: file bluh
Вихід: bluh: directory
ls
Команда в поєднанні з -l
(довгий список) повертає опціонних атрибути інформації про файлах і каталогах.
Зокрема, першим символом ls -l
виводу це, як правило, d
або a -
(тире). У випадку 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: / x: Немає такого файлу чи каталогу", якщо каталог або symlink не існує, а також встановлює код повернення, який ви можете отримати через "$?", На не -null (зазвичай "1"). Не забудьте перевірити код повернення безпосередньо після виклику "ls".
if ! ls $DIR 2>/dev/null; then echo "$DIR does not exist!"; fi
(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 exists || not exists
-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
буде успішно виконано лише в тому випадку, якщо на момент виконання ви знаходитесь в каталозі, в якому є підкаталог, на який ви маєте перевіритись.
Я розумію початкове запитання таким чином: перевірити, чи існує каталог незалежно від положення користувача у файловій системі. Тож використання команди «знайти» може зробити трюк:
dir=" "
echo "Input directory name to search for:"
read dir
find $HOME -name $dir -type d
Це рішення хороше тим, що дозволяє використовувати підстановку, корисну функцію при пошуку файлів / каталогів. Єдина проблема полягає в тому, що якщо шуканий каталог не існує, команда 'find' нічого не надрукує до стандартного виводу (не елегантне рішення на мій смак) і тим не менше матиме нульовий вихід. Можливо, хтось міг би покращити це.
locate
але не приємно ні для чого іншого ...
--
дуже рекомендується використовувати маркер кінця опцій. В іншому випадку, якщо ваша змінна містить щось, що схоже на опцію, сценарій вийде з ладу так само, як і пробілами.