Какую команду можно использовать для проверки наличия каталога в сценарии оболочки Bash?
Как я могу проверить, существует ли каталог в сценарии оболочки Bash?
Ответы (35)
Чтобы проверить, существует ли каталог в сценарии оболочки, вы можете использовать следующее:
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 объясняет в другом ответе.
Если переменные содержат пробелы или другие необычные символы, это, вероятно, приведет к сбою сценария.
Согласно комментарию Джонатана:
Если вы хотите создать каталог, а он еще не существует, то самый простой способ - использовать mkdir -p
, который создает каталог - и любые отсутствующие каталоги вверх по пути - и не завершится ошибкой, если каталог уже существует, так что вы можете сделать все сразу с помощью:
mkdir -p /some/directory/you/want/to/exist || exit 1
DIRECTORY=/tmp
if [ -d "$DIRECTORY" ]; then
echo "Exists"
fi
запомнить space
после [
-> [`` -d . у меня ошибка из-за отсутствия места
СНОВА, этот ответ уже был дан в 2008 году с более полезными объяснениями. Единственная новинка здесь - онлайн-площадка.
В качестве альтернативы параметрам «[-d]» и «[-h]» вы можете использовать stat
для получения типа файла и его анализа.
#! /bin/bash
MY_DIR=$1
NODE_TYPE=$(stat -c '%F' ${MY_DIR} 2>/dev/null)
case "${NODE_TYPE}" in
"directory") echo $MY_DIR;;
"symbolic link") echo $(readlink $MY_DIR);;
"") echo "$MY_DIR does not exist";;
*) echo "$NODE_TYPE is unsupported";;
esac
exit 0
Тестовые данные:
$ mkdir tmp
$ ln -s tmp derp
$ touch a.txt
$ ./dir.sh tmp
tmp
$ ./dir.sh derp
tmp
$ ./dir.sh a.txt
regular file is unsupported
$ ./dir.sh god
god does not exist
Используйте программу file
.
Учитывая, что все каталоги в Linux также являются файлами, достаточно выполнить следующую команду:
file $directory_name
Проверка несуществующего файла: file blah
Вывод: cannot open 'blah' (No such file or directory)
Проверка существующего каталога: file bluh
Вывод: bluh: directory
Хорошая идея, но слишком плохая в обоих случаях, команда file всегда возвращает 0 код выхода. Также, когда файл / каталог не может быть найден :(.
-
Простой сценарий для проверки наличия каталога или файла:
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: файл существует
Второй создаст каталог, если сначала его не было. Тогда это не идемпотент.
👆👆👆. Второй кажется опасным. Поскольку он создает каталог, это даже не правда, что каталог отсутствует.
mkdir также не создаст полный путь (без параметра), но обратное будет еще более опасным, так как вы даже не можете отменить (rm -f) изменения, поскольку вы не знаете, какие каталоги он создал
Думали ли вы, что просто делать то, что вы хотите, в 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
.
pushd - для меня самый элегантный способ сделать это. Я собирался опубликовать это как ответ :)
Git Bash + Dropbox + Windows:
Ни одно из других решений не помогло моей папке Dropbox, что было странно, потому что я могу Git нажать на символический путь Dropbox.
#!/bin/bash
dbox="~/Dropbox/"
result=0
prv=$(pwd) && eval "cd $dbox" && result=1 && cd "$prv"
echo $result
read -p "Press Enter To Continue:"
Вы, вероятно, захотите узнать, как успешно перейти к Dropbox из Bash. Итак, вот сценарий целиком.
cd -
может сильно упростить это ... Или cd "$OLDPWD"
(Или используйте подоболочку, в которой каталог вашего скрипта не изменяется, но тогда вы не можете устанавливать переменные)
Из файла сценария myScript.sh :
if [ -d /home/ec2-user/apache-tomcat-8.5.5/webapps/Gene\ Directory ]; then
echo "Directory exists!"
echo "Great"
fi
или
if [ -d '/home/ec2-user/apache-tomcat-8.5.5/webapps/Gene Directory' ]; then
echo "Directory exists!"
echo "Great"
fi
В виде тройной формы,
[ -d "$directory" ] && echo "exist" || echo "not exist"
И с test
:
test -d "$directory" && echo "exist" || echo "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";
Проверьте, существует ли каталог, иначе создайте его:
[ -d "$DIRECTORY" ] || mkdir $DIRECTORY
Вы можете использовать mkdir -p "$DIRECTORY"
для того же эффекта.
Также нужны двойные кавычки вокруг $DIRECTORY
в части mkdir
. В противном случае разбиение слов может привести к нежелательным результатам. Например: dir="a b"; mkdir $dir
приведет к созданию двух каталогов a
и b
, а не одного каталога a b
.
Чтобы проверить более одного каталога, используйте этот код:
if [ -d "$DIRECTORY1" ] && [ -d "$DIRECTORY2" ] then
# Things to do
fi
как проверить, что его не существует?
Вы можете использовать test -d
(см. man test
).
-d file
Истинно, если файл существует и является каталогом.
Например:
test -d "/etc" && echo Exists || echo Does not exist
Примечание. Команда test
аналогична условному выражению [
(см .: man [
), поэтому ее можно переносить между сценариями оболочки.
[
- это синоним встроенной функцииtest
, но последний аргумент должен быть буквальным]
, чтобы соответствовать открытию[
.
Чтобы узнать о возможных вариантах или дополнительной помощи, проверьте:
help [
help test
-
man test
илиman [
(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: not: not found [Нет такого файла или каталога]
Что означает "выше"? Три командные строки в этом ответе или предыдущих ответах? (Пожалуйста, ответьте, отредактировав свой ответ, а не здесь, в комментариях. Заранее спасибо.).
[[ -d "$DIR" && ! -L "$DIR" ]] && echo "It's a directory and not a symbolic link"
Примечание: рекомендуется указывать переменные в кавычках.
Пояснение :
-
-d
: проверьте, является ли это каталог -
-L
: проверьте, является ли это символической ссылкой
Пояснение будет в порядке (отредактировав свой ответ, а не здесь, в комментариях).
Чтобы проверить, существует ли каталог, вы можете использовать простую структуру 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
Чем это лучше, чем принятый ответ от 2008 года, если не считать выхода за рамки темы с переключателями файлов?
лучше из-за [! -d каталог / путь к каталогу]
Введите этот код в командной строке Bash:
if [ -d "$DIRECTORY" ]; then
# If true this block of code will execute
fi
СНОВА, этот ответ уже давался в 2008 году. Какой смысл его повторять ?!
Если вы хотите проверить, существует ли каталог, независимо от того, настоящий ли это каталог или символическая ссылка, используйте это:
ls $DIR
if [ $? != 0 ]; then
echo "Directory $DIR already exists!"
exit 1;
fi
echo "Directory $DIR does not exist..."
Объяснение: Команда «ls» выдает ошибку «ls: / x: Нет такого файла или каталога», если каталог или символическая ссылка не существует, а также устанавливает код возврата, который можно получить с помощью «$?». , на ненулевое значение (обычно "1"). Убедитесь, что вы проверили код возврата сразу после вызова «ls».
В качестве альтернативы вы можете использовать эту более короткую версию: if ! ls $DIR 2>/dev/null; then echo "$DIR does not exist!"; fi
ls
возврат ненулевого значения НЕ означает, что каталог существует. Код должен быть: ls $DIR RETURN_CODE=$? if [ "$RETURN_CODE" != "0" ]; then echo "Cannot access directory $DIR (does not exist or no permission or something else altogether)!" exit $RETURN_CODE; fi echo "Directory $DIR already exists..."
Использование проверки -e
будет проверять файлы, в том числе каталоги.
if [ -e ${FILE_PATH_AND_NAME} ]
then
echo "The file or directory exists."
fi
И не правильно отвечает на вопрос ОП - это каталог?
[ -d ~/Desktop/TEMPORAL/ ] && echo "DIRECTORY EXISTS" || echo "DIRECTORY DOES NOT EXIST"
Пояснение будет в порядке (отредактировав свой ответ, а не здесь, в комментариях).
file="foo"
if [[ -e "$file" ]]; then echo "File Exists"; fi;
Пояснение будет в порядке (отредактировав свой ответ, а не здесь, в комментариях).
Вот очень прагматичная идиома:
(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
справочной страницы:
${parameter:?word}
Если установлено значение
parameter
и не равно нулю, замените его значение; в противном случае выведитеword
и выйдите из оболочки (если не интерактивно). Еслиword
опущено, печатается стандартное сообщение.
и
Если двоеточие
:
опущено в приведенных выше выражениях, то оболочка только проверяет, установлен ли параметр или нет.
Формулировка здесь специфична для документации оболочки, поскольку word
может относиться к любой разумной строке, включая пробелы.
В этом конкретном случае я знаю, что стандартного сообщения об ошибке 1: parameter not set
недостаточно, поэтому я увеличиваю тип значения, которое мы ожидаем здесь - pathname
каталога.
Философское примечание:
Оболочка не является объектно-ориентированным языком, поэтому в сообщении написано pathname
, а не directory
. На этом уровне я бы предпочел упростить - аргументы функции - это просто строки.
Это больше, чем просто проверка на существование: это проверка доступности на вашем уровне пользователя. ТАК вопрос стоит только для существования . Итак, правильный ответ - test -d
, как объяснил @Grundlefleck.
@ F.Hauri - Он больше ничего не просил, это правда. Однако я обнаружил, что мне обычно нужно знать больше.
И мне никогда не приходило в голову, что ни один тест не может быть окончательным, если он не запущен от имени пользователя root. test -d /unreadable/exists
завершится ошибкой, даже если аргумент существует.
Существуют отличные решения, но в конечном итоге каждый сценарий завершится ошибкой, если вы не в правильном каталоге. Итак, код вроде этого:
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 ничего не выведет на стандартный вывод (не изящное решение на мой вкус) и, тем не менее, будет иметь нулевой выход. Может быть, кто-нибудь сможет это улучшить.
Я был бы оскорблен, если бы программа просматривала весь мой жесткий диск в поисках каталога, а не просто вежливо просматривала мой текущий рабочий каталог или использовала абсолютный путь, который я ей указывал. То, что вы предложили, может быть хорошо для инструмента с именем locate
, но не годится ни для чего другого ...
Команда 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
+1, но если ISDIR вообще не существует, вы получите сообщение об ошибке, а также диагностическое сообщение.
if [ -d "$Directory" -a -w "$Directory" ]
then
#Statements
fi
Приведенный выше код проверяет, существует ли каталог и доступен ли он для записи.
-a по сути совпадает с -e. Он объявлен устаревшим, и его использование не рекомендуется.
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
На самом деле вам следует использовать несколько инструментов, чтобы получить пуленепробиваемый подход:
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), преимущество заключается в больше, чем проблема.
Или что-то совершенно бесполезное:
[ -d . ] || echo "No"
Он никогда не напечатает «Нет». Текущий каталог всегда существует, если он не удален другим потоком или другими способами.
Идеальный образец :) учитывая, насколько "уникальны" некоторые ответы по сравнению с принятым ответом
Почему за это так много раз голосовали? Это не отвечает на вопрос.
Не забывайте всегда заключать переменные в двойные кавычки при обращении к ним в сценарии Bash. В наши дни дети растут с мыслью, что в названиях каталогов могут быть пробелы и много других забавных персонажей. (Пробелы! В мои дни у нас не было шикарных пространств!;))
Однажды один из этих детей запустит ваш скрипт с $DIRECTORY
, установленным на "My M0viez"
, и ваш скрипт взорвется. Вы этого не хотите. Так что используйте это.
if [ -d "$DIRECTORY" ]; then
# Will enter here if $DIRECTORY exists, even if it contains spaces
fi
Еще одна причина использовать двойные кавычки - это если по какой-то причине $ DIRECTORY не установлен.
«всегда заключайте переменные в двойные кавычки ... в сценарии bash». Для bash технически не требуется при использовании [[...]]; см. tldp.org/LDP/abs/html/testconstructs.html#DBLBRACKETS (примечание: без разделения слов): «Между [[и]] не выполняется расширение имени файла или разделение слов, но есть параметр расширение и подстановка команд ".
В каталогах в Unix / Linux не должно быть пробелов, и впоследствии скрипты не должны быть адаптированы к ним. Достаточно плохо, что Windows поддерживает это со всеми последствиями для сценариев Windows, но, пожалуйста, из любви к чему бы то ни было, не нужно вводить ненужные требования.
@tvCa Я считаю, что пользователи обычно предпочитают, чтобы им была предоставлена большая гибкость в именах каталогов, вместо того, чтобы их заставляли упростить работу для разработчиков. (На самом деле, когда я имею дело с длинными именами файлов, я считаю, что файлы без пробелов вызывают боль, поскольку это убивает перенос слов, хотя я сам в прошлом страдал из-за того, что не учитывал пути с пробелами в скриптах и программах.)
@JAB Я согласен, но опять же, такие длинные имена каталогов требуют создания нескольких каталогов и лучшей сортировки / категоризации / организации файлов в них.
Это действительно отдельный вопрос; coderhelper.com/questions/10067266/…
Ха. Пробелы - это просто символы, у которых обычно нет глифов. В любом случае, вы можете избежать их с помощью обратной косой черты.
@tvCa Многие сценарии, которые были счастливы в стандартных средах * nix, внезапно оказываются в средах Windows (вспомните cygwin или git для Windows / Msys2). Или они просто лежат на общих ресурсах Samba. Неслучайно все больше и больше инструментов получают возможность создавать или обрабатывать имена файлов с завершающим NUL.
Еще одно преимущество использования переменных в кавычках: производительность - Bash не нужно пытаться разбивать слова на содержимое строки в кавычках. (В основном это ничтожно мало)
IFS="\t\n"
очень помогает в сценариях оболочки при работе с пробелами в именах файлов / именах каталогов (где \ t - фактический символ табуляции, а \ n - фактический LF, поэтому он занимает две строки в скрипте :)
Ваш сценарий взорвется с помощью "~ / my_dir", без ума от детей.
Пробелы в именах файлов - зло, я сейчас выполняю миссию с Wowbagger the Infininite Prolonged, чтобы оскорбить всех, кто их использует :-)
Я считаю, что версия с двумя скобками test
делает написание логических тестов более естественным:
if [[ -d "${DIRECTORY}" && ! -L "${DIRECTORY}" ]] ; then
echo "It's a bona-fide directory"
fi
для if [[ -d "$TARFILE" ]]
Я получаю [[: не найдено
@TheVillageIdiot и @Hedgehog, вы используете оболочку bash? Двойная скобка поддерживается не везде. Вот ТАК ответ на этот вопрос: coderhelper.com/questions/669452/…
А в Busybox ash с параметрами компиляции по умолчанию поддерживается [[ ]]
, но на самом деле он не предоставляет никаких функций, отличных от [ ]
. Если переносимость вызывает беспокойство, придерживайтесь [ ]
и используйте необходимые обходные пути.
... при использовании конструкций bash в сценарии оболочки первая строка сценария должна быть: #! / bin / bash (а не #! / bin / sh, ksh и т. д.)
При использовании двойных квадратных скобок в bash не нужно заключать переменные в кавычки.
Переносимая версия этого ответа для Posix - if [ -d "$DIRECTORY" ] && ! [ -h "$DIRECTORY ]; then …
(-L
устарела, -h
- его замена. Используйте -L
, если вы используете действительно древнюю систему Unix).
@AdamKatz: -L
устарел? В какой системе? Ни help test
в Bash, ни справочная или информационная страница GNU coreutils не упоминают об этом.
@SorenBjornstad - устаревшее - неправильное слово, но на странице руководства для dash
говорится: «Этот оператор сохранен для совместимости с предыдущими версиями этой программы. Не полагайтесь на его существование; используйте вместо него -h
».
@AdamKatz Переносимость и отказ от функций в dash не имеют значения, поскольку речь идет о bash.
Более короткая форма:
# if $DIR is a directory, then print yes
[ -d "$DIR" ] && echo "Yes"
Это работает так: if $dir is a dir, then echo "yes"
? Небольшое объяснение поможет :)
cmd && other
- это обычное сокращение для if cmd; then other; fi
- это работает с большинством языков программирования, поддерживающих логику, и известно как оценка короткого замыкания.
Поведение отличается от set -e
(что является передовой практикой программирования оболочки).
@dolmen проверяется [ -d "$DIR" ]
(за ним следует && echo Yes
), поэтому я считаю, что set -e
не влияет на поведение скрипта (т.е. если тест не проходит, скрипт продолжает нормально).
Обратите внимание, что тест -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 и [
встроенной команде и <984099956329840> составной запятой <984099956329840>.
или, предполагая, что необходимо работать только с каталогами (и ссылки можно игнорировать) => if [ -d tmpdir -a ! -L tmpdir ]; then echo "is directory"; rmdir tmpdir; fi
... или для одной команды, которая работает как с ссылками, так и с каталогами: rm -r tmpdir
Дополнительные функции с использованием 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'
. Вы не возражаете, если я добавлю в ваш ответ этот трюк? Ваше здоровье ;)
Если вы хотите перестраховаться с инструментами GNU, настоятельно рекомендуется использовать
--
(маркер конца опций). В противном случае, если ваша переменная содержит что-то похожее на параметр, сценарий завершится ошибкой, как и с пробелами.Для современных версий bash, ksh и т. Д. [...] является встроенным
Следует иметь в виду одну вещь:
[ ! -d "$DIRECTORY" ]
будет истинным либо если$DIRECTORY
не существует, либо если существует, но не является каталогом. Рассмотрим что-то вродеif [ ! -d "$DIRECTORY" ] ; then mkdir "$DIRECTORY" ; fi
; это не удастся, если"$DIRECTORY"
является файлом. (Конечно, вы все равно должны проверить, удалось ли выполнитьmkdir
; есть ряд причин, по которым он может потерпеть неудачу.)Незначительное примечание. В bash, help [, man test (как уже отмечалось) и info test («Не для UNIX») предоставляют документацию.
я должен использовать
[ ]
или[[ ]]
?Стоит отметить, что как только проверка была проведена, ситуация может измениться уже из-за других процессов. Во многих случаях лучше просто создать или использовать каталог и реагировать на сбой.
По какой-то причине я получаю сообщение об ошибке:
if [ -d "$TARGET_DIR/$DATE1" ]; then $RSYNC_PARAMS="$RSYNC_PARAMS --link-dest=$TARGET_DIR/$DATE1" fi
DATE1='date -I -d "1 day ago"'
;TARGET_DIR="/backup"
, который является ссылкой;RSYNC_PARAMS="-azrtplH"
Вместо тестирования каталога (
-d
) и символической ссылки (-L
) проще просто добавить косую черту к переменной, напримерif [ -d "${THING:+$THING/}" ]
. Каталог не будет возражать против лишней косой черты. Оценка файла будет ложной. Empty останется пустым, поэтому false. И символическая ссылка будет разрешена по назначению. Конечно, это зависит от вашей цели. Если вы хотите перейти туда , это нормально. Если вы хотите удалить его , то код в этом ответе лучше.Использование test НЕ работает с отключенным USB-накопителем, поскольку журналирующая FS делает вид, что каталог все еще существует, если вы уже проверяли его ранее. Я обнаружил, что в этом случае проверка кода выхода ls была единственным способом надежно проверить, существует ли каталог:
if ls "$DIRECTORY"; then echo "dir exists" ; fi
Почему это не работает для относительных путей? Например,
../../../../../my_dir
.Есть ли разница между
-L
и-h
? На этом веб-сайте gnu.org/savannah-checkouts/gnu/bash/manual/… говорится, что они обаTrue if file exists and is a symbolic link.
Так в чем разница?Пробелы в пределах
[
и]
, вокруг-d
или! -d
важны, иначе сценарий завершится ошибкой, и команда не найдена.