Проверьте, существует ли каталог в сценарии оболочки

3177

Какую команду можно использовать для проверки наличия или отсутствия каталога в оболочке script?

Теги:
posix

34 ответа

4173
Лучший ответ

Чтобы проверить, существует ли каталог в сценарии оболочки, вы можете использовать следующее:

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 a directory!
    # Directory command goes here.
    rmdir "$LINK_OR_DIR"
  fi
fi

Обратите особое внимание на двойные кавычки, используемые для переноса переменных, причина этого объясняется 8jean в другом ответе.

Если переменные содержат пробелы или другие необычные символы, это может привести к сбою сценария.

  • 24
    Если вы хотите быть осторожнее с инструментами GNU, настоятельно рекомендуется использовать -- (маркер конца опций). В противном случае, если ваша переменная содержит нечто, похожее на параметр, скрипт завершится с ошибкой, как и с пробелами.
  • 2
    Для современных версий bash, ksh и т. Д. [...] является встроенным
Показать ещё 10 комментариев
477

Не забудьте всегда переносить переменные в двойные кавычки, ссылаясь на них в a bash script. Дети в эти дни растут с идеей, что они могут иметь пробелы и множество других забавных персонажей в своих именах каталогов. (Пространства! В мои дни у нас не было никаких фантастических пространств!))

Однажды один из этих детей запустит ваш script с $DIRECTORY, установленным на "My M0viez", и ваш script взорвется. Вы этого не хотите. Поэтому используйте это.

if [ -d "$DIRECTORY" ]; then
    # Will enter here if $DIRECTORY exists, even if it contains spaces
fi
  • 8
    Другая причина использовать двойные кавычки в том случае, если $ DIRECTORY не установлен по какой-либо причине.
  • 2
    msgstr "всегда заключать переменные в двойные кавычки ... в скрипте bash." Для bash, технически не требуется при использовании [[...]]; см. tldp.org/LDP/abs/html/testconstructs.html#DBLBRACKETS (примечание: без разделения слов): «Не происходит расширения имени файла или разделения слова между [[и]], но есть расширение параметра и подстановка команд».
Показать ещё 9 комментариев
204

Обратите внимание, что тест -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 условных выражениях и [ встроенная команда и [[ составная комм..

  • 12
    или, предполагая, что необходимо работать только с каталогами (а ссылки можно игнорировать) => if [ -d tmpdir -a ! -L tmpdir ]; then echo "is directory"; rmdir tmpdir; fi ... или, для одной команды, которая работает с обоими ссылками и каталогами: rm -r tmpdir
189

Я нахожу версию с двумя скобками test делает естественные логические тесты написания:

if [[ -d "${DIRECTORY}" && ! -L "${DIRECTORY}" ]] ; then
    echo "It a bona-fide directory"
fi
  • 0
    if [[ -d "$TARFILE" ]] я получаю [[: не найдено
  • 0
    то же самое [[: не найдено
Показать ещё 4 комментария
125

Более короткая форма:

[ -d "$DIR" ] && echo "Yes"
  • 3
    Работает ли это так: if $dir is a dir, then echo "yes" ? Немного объяснения поможет :)
  • 5
    cmd && other - это обычное сокращение для if cmd; then other; fi - это работает с большинством языков программирования, которые поддерживают булеву логику, и называется оценкой короткого замыкания .
Показать ещё 2 комментария
114

Чтобы проверить, существует ли каталог, вы можете использовать простую структуру, например:

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 
90
if [ -d "$DIRECTORY" ]; then  
    # Here if $DIRECTORY exists  
fi
71

Вы можете использовать test -d (см. man test).

-d file Истина, если файл существует и является каталогом.

Например:

test -d "/etc" && echo Exists || echo Does not exist

Примечание. Команда test такая же, как условное выражение [ (см. man [), поэтому оно переносится по сценариям оболочки.

[ - Это синоним встроенного test, но последний аргумент должен быть буквальным ], чтобы соответствовать открытию [.

Для получения возможных вариантов или дополнительной помощи проверьте:

  • help [
  • help test
  • man test или man [
52

Или для чего-то совершенно бесполезного:

[ -d . ] || echo "No"
  • 5
    Он никогда не напечатает «Нет». Текущий каталог всегда существует, если только он не удален другим потоком или другими способами.
  • 0
    Идеальный образец :) учитывая, насколько «уникальны» некоторые ответы по сравнению с принятым ответом
Показать ещё 1 комментарий
44

Здесь очень прагматичная идиома:

(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}. Это более сложная форма замещения параметров, которая более подробно объясняется ниже.

Tl; dr: Если строка, переданная в эту функцию, пуста, мы снова выходим из подоболочки ( ... ) и возвращаемся от функции с данным сообщением об ошибке.


Цитата из справочной страницы ksh93:

${parameter:?word}

Если parameter установлено и не равно null, замените его значение; в противном случае напечатайте word и выйдите из оболочки (если не интерактивно). Если word опущено, выводится стандартное сообщение.

и

Если двоеточие : не указано в приведенных выше выражениях, shell проверяет, установлен ли параметр или нет.

Обозначение здесь относится к документации оболочки, поскольку word может ссылаться любой разумной строке, включая пробелы.

В этом конкретном случае я знаю, что стандартное сообщение об ошибке 1: parameter not set недостаточно, поэтому я увеличиваю тип ожидаемого здесь значения - pathname каталога.

Философская заметка: Оболочка не является объектно-ориентированным языком, поэтому сообщение говорит pathname, а не directory. На этом уровне я бы предпочел сохранить его простым - аргументы функции являются просто строками.

  • 0
    Это больше, чем просто проверка на наличие: эта проверка на доступность на вашем уровне пользователя. ТАК вопрос стоять только за существование . Итак, правильный ответ - test -d как объяснил @Grundlefleck.
  • 6
    @ F.Hauri - Он больше ничего не просил, это правда. Однако я обнаружил, что обычно мне нужно знать больше, чем это.
Показать ещё 1 комментарий
34
if [ -d "$Directory" -a -w "$Directory" ]
then
    #Statements
fi

Вышеприведенный код проверяет, существует ли каталог и доступен ли он.

  • 1
    -a фактически идентичен -e. Это было "устарело", и его использование не рекомендуется.
24

Введите этот код в bash promt

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

Собственно, вы должны использовать несколько инструментов для получения пуленепробиваемого подхода:

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 a dir";
fi

Не нужно беспокоиться о пробелах и специальных символах, пока вы используете "${}".

Обратите внимание, что [[]] не так переносится, как [], но поскольку большинство людей работают с современными версиями Bash (поскольку в конце концов большинство людей даже не работают с командной строкой: -p), выгода больше, чем проблема.

19

Дополнительные функции с использованием 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
    
  • 0
    Привет ниль Ваша идея может быть полезна для проверки существования каталогов в зависимости от шаблона, например: find -maxdepth 1 -type d -name 'pattern' . Вы не против, если я добавлю в ваш ответ этот трюк? Ура;)
16
  1. Простой скрипт для проверки наличия или отсутствия файла или файла:

    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
    

    Вышеприведенные скрипты будут проверять, присутствует ли каталог или нет.

    $? если последний успешный процесс возвращает значение "0" else, отличное от нуля. предположим, что tempdir уже присутствует, тогда mkdir tempdir даст ошибку, как mkdir tempdir ниже:

    mkdir: невозможно создать каталог tempdir: Файл существует

  • 0
    Ваш второй скрипт слишком большой, чем 1-й
  • 0
    Второй создаст каталог, если его сначала не было. Тогда это не идемпотент.
16

Чтобы проверить несколько каталогов, используйте этот код:

if [ -d "$DIRECTORY1" ] && [ -d "$DIRECTORY2" ] then
    # Things to do
fi
  • 0
    как вы можете проверить, что он не существует?
15

Вы считали, что просто делаете то, что хотите делать, if хотите, а не смотрите, прежде чем прыгать?

IE, если вы хотите проверить наличие каталога, прежде чем вводить его, попробуйте сделать это:

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 cd, mv, rm, и т.д... если вы попробуете их на файлы, которые не существуют, они будут выходить с ошибкой и распечатать сообщение о том, что не существует, и ваш, then блок будет пропускаются. Если вы попробуете их в существующих файлах, команда выполнит и завершит со статусом 0, что позволит выполнить then блок.

  • 2
    pushd для меня самый элегантный способ сделать это. Я собирался опубликовать это как ответ :)
14

Проверьте, существует ли каталог, иначе сделайте один

[ -d "$DIRECTORY" ] || mkdir $DIRECTORY
  • 15
    Вы можете использовать mkdir -p "$DIRECTORY" для того же эффекта.
14
[[ -d "$DIR" && ! -L "$DIR" ]] && echo "It a directory and not a symbolic link"

N.B: Котировочные переменные являются хорошей практикой.

12
[ -d ~/Desktop/TEMPORAL/ ] && echo "DIRECTORY EXISTS" || echo "DIRECTORY DOES NOT EXIST"
11

Этот ответ завершен как оболочка script

Примеры

$ 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";
9

Использование проверки -e будет проверять файлы, включая каталоги.

if [ -e ${FILE_PATH_AND_NAME} ]
then
    echo "The file or directory exists."
fi
  • 1
    неверно для папки с пробелами
  • 0
    И не правильно отвечает на вопрос ОП - это каталог?
8

По Jonathan комментарий:

Если вы хотите создать каталог, и он еще не существует, то самым простым методом является использование mkdir -p, который создает каталог - и любые отсутствующие каталоги до пути - и не прерывается, если каталог уже существует, поэтому вы можете сделать все сразу:

mkdir -p /some/directory/you/want/to/exist || exit 1
7
if [ -d "$DIRECTORY" ]; then
    # Will enter here if $DIRECTORY exists
fi

Это не совсем так... Если вы хотите перейти в этот каталог, вам также необходимо иметь права на выполнение в каталоге. Возможно, вам также нужны права на запись.

Therfore:

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
6

Команда 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
  • 0
    +1, но если ISDIR вообще не существует, вы получаете сообщение об ошибке, а также диагностическое сообщение.
5

(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]] && & эхо существует || не существует -ksh: not: not found [Нет такого файла или каталога]

5

Если вы хотите проверить, существует ли каталог, независимо от того, является ли это реальной директорией или символической ссылкой, используйте это:

ls $DIR
if [ $? != 0 ]; then
        echo "Directory $DIR already exists!"
        exit 1;
fi
echo "Directory $DIR does not exist..."

Объяснение: Команда "ls" дает ошибку "ls:/x: Нет такого файла или каталога", если каталог или символическая ссылка не существует, а также устанавливает код возврата, который вы можете получить с помощью "$?"., до ненулевой (обычно "1" ). Обязательно проверьте код возврата непосредственно после вызова "ls".

  • 3
    В качестве альтернативы вы можете использовать эту более короткую версию: if ! ls $DIR 2>/dev/null; then echo "$DIR does not exist!"; fi
5
file="foo" 
if [[ -e "$file" ]]; then echo "File Exists"; fi;
4

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. Итак, вот в нем script.

https://pastebin.com/QF2Exmpn

  • 0
    cd - может сильно упростить это ... Или cd "$OLDPWD" (или использовать подоболочку, которая не меняется в cd "$OLDPWD" вашего скрипта, но тогда вы не можете устанавливать переменные)
4

Ниже можно использовать

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

Отличные решения там, но в конечном итоге каждый script завершится неудачно, если вы не находитесь в правильном каталоге. Итак, код выглядит следующим образом:

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 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

Это решение хорошо, потому что оно позволяет использовать подстановочные знаки, полезную функцию при поиске файлов/каталогов. Единственная проблема заключается в том, что если искомый каталог не существует, команда "найти" ничего не выведет на stdout (не элегантное решение на мой вкус) и, тем не менее, будет иметь нулевой выход. Может быть, кто-то может улучшить это.

  • 13
    Я был бы обижен, если бы программа просматривала весь мой жесткий диск, чтобы найти каталог, а не просто вежливо просматривала мой текущий рабочий каталог или использовала абсолютный путь, который я ему дал. То, что вы предложили, может быть полезным для инструмента с именем locate но не подходит ни для чего другого ...
3

Как насчет file программы. Учитывая, что все каталоги также являются файлами в linux, достаточно выполнить следующую команду:

file $directory_name

Проверка несуществующего файла: file blah

Выход: cannot open 'blah' (No such file or directory)

Проверка существующего каталога: file bluh

Выход: bluh: directory

2

Из Script файла 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 
  • 0
    Дубликат первого ответа. Пожалуйста, не голосуйте.
1

В виде тройной формы

[ -d "$directory" ] && echo "exist" || echo "not exist"

И с тестом

test -d "$directory" && echo "exist" || echo "not exist"

Ещё вопросы

Сообщество Overcoder
Наверх
Меню