Какую команду можно использовать для проверки, существует ли каталог в сценарии оболочки 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
), и symlink ( -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
страницы:
${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
выполнить ваш блок.
[[ -d "$DIR" && ! -L "$DIR" ]] && echo "It's a directory and not a symbolic link"
Примечание: цитирование переменных - это хорошая практика.
Объяснение:
-d
: проверьте, если это каталог-L
: проверьте, если это символическая ссылкаЧтобы проверить более одного каталога, используйте этот код:
if [ -d "$DIRECTORY1" ] && [ -d "$DIRECTORY2" ] then
# Things to do
fi
Проверьте, существует ли каталог, иначе создайте его:
[ -d "$DIRECTORY" ] || mkdir $DIRECTORY
mkdir -p "$DIRECTORY"
для того же эффекта.
[ -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
или или -
(тире). В случае, 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: Нет такого файла или каталога", если каталог или символическая ссылка не существует, а также устанавливает код возврата, который вы можете получить с помощью "$?", На значение non -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: not: not found [Нет такого файла или каталога]
Есть отличные решения, но в конечном итоге каждый сценарий потерпит неудачу, если вы не в нужном каталоге. Так что код такой:
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
но не хорошим для всего остального ...
--
настоятельно рекомендуется использовать их (маркер конца опций). В противном случае, если ваша переменная содержит нечто, похожее на параметр, скрипт завершится с ошибкой, как и с пробелами.